You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AppHost.RunAsync()无限挂起问题排查求助

问题描述

运行一个通过Autofac配置了Windows后台服务、邮件服务、日志及DI对象的应用时,AppHost.RunAsync()出现无限挂起,无法返回控制权。此前代码运行正常,多次运行后才触发该问题。已确认服务注册无异常,即使仅保留日志、ProcessorOptions等基础服务,AppHost仍无法正常运行,求排查方向。


Program.cs

private static async Task Main(string[] args)
{
    try
    {
        Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
        LogManager.Configuration = new XmlLoggingConfiguration("NLog.config");
        log = LogManager.GetCurrentClassLogger();
        var builder = Host.CreateDefaultBuilder(args);
        AppHost = builder
             .UseServiceProviderFactory(ctx =>
             {
                 AutofacConfiguration.Configuration = ctx.Configuration;
                 return new AutofacServiceProviderFactory(AutofacConfiguration.BuildContainer);
             })
            .ConfigureServices((ctx, services) =>
            {                      
                var svcOptions = ctx.Configuration.GetSection(ServiceEntryPointOptions.ConfigSectionName).Get<ServiceEntryPointOptions>();
                WindowsBackgroundService.WindowsServiceKey = $"{svcOptions.ServiceName}${svcOptions.InstanceName}";

                services.AddHostedService<WindowsBackgroundService>();
            })
            .UseWindowsService(options =>
            {
                options.ServiceName = WindowsBackgroundService.WindowsServiceKey;
            })
            .Build();
        await AppHost.RunAsync();
    }
    catch (Exception e)
    {

    }
    finally
    {
        AppHost?.Dispose();
    }
}

AutofacConfiguration.cs

public partial class AutofacConfiguration
{
    public static IConfiguration Configuration { get; set; }
    public static NLog.ILogger AppLogger { get; } = LogManager.GetLogger("Logger");

    private static readonly ILogger Log = LogManager.GetCurrentClassLogger();

    public static void BuildContainer(ContainerBuilder builder)
    {
        #region Container configuration

        try
        {
            #region Library Configuration

            builder.RegisterInstance(AppLogger)
                .As<NLog.ILogger>()
                .SingleInstance();

            #endregion

            #region Application specific types

            builder.RegisterOptions<ServiceEntryPointOptions>(Configuration, ServiceEntryPointOptions.ConfigSectionName);

            // Used by DeadletterErrorHandler
            builder.RegisterType<ServiceStoppingService>()
                .As<IServiceStoppingService>()
                .SingleInstance();
            builder.RegisterType<LifecycleService>().As<ILifecycleAsync>();

            builder.RegisterRmqConnectionManager(Configuration, RmqConnectionManagerOptions.ConfigSectionName);
            builder.RegisterRmqMessageHandler(Configuration, RmqMessageHandlerOptions.ConfigSectionName);
            builder.RegisterEmailNotificationServiceOptions(Configuration, EmailNotificationServiceOptions.ConfigSectionName);

            #endregion
        }
        catch (Exception e)
        {
            Log.Error(e);

            throw;
        }

        #endregion
    }
}

AutofacConfigurationExtension.cs

public static class AutofacConfigurationExtensions
{
   public static ContainerBuilder RegisterOptions<TOptions>(
   this ContainerBuilder builder,
   IConfiguration config,
   string sectionName,
   string name = null
   )
   where TOptions : class, new()
    {
        var section = config.GetRequiredSection(sectionName);
        var options = section.Get<TOptions>();
        var accessor = new OptionsWrapper<TOptions>(options);

        var item = builder.RegisterInstance(options);
        item = name switch { null => item.As<TOptions>(), _ => item.Named<TOptions>(name) };
        item.SingleInstance();

        var item2 = builder.RegisterInstance(accessor);
        item2 = name switch { null => item2.As<IOptions<TOptions>>(), _ => item2.Named<IOptions<TOptions>>(name) };
        item2.SingleInstance();

        return builder;
    } 
public static ContainerBuilder RegisterRmqConnectionManager(this ContainerBuilder builder,
            IConfiguration config,
            string sectionName,
            string name = null)
        {
            builder.RegisterOptions<RmqConnectionManagerOptions>(config, sectionName, name);
            builder.RegisterType<RmqConnectionManager>()
                .As<IRmqConnectionManager>()
                .PropertiesAutowired();
           return builder;

        }
        
         public static ContainerBuilder RegisterRmqMessageHandler(this ContainerBuilder builder,
     IConfiguration config,
     string sectionName,
     string name = null)
 {
     builder.RegisterType<DbRepository>()
         .As<IDomainRepository>();
     builder.RegisterType<FileParser>()
         .As<IFileParser>();
     builder.RegisterType<FileReader>()
         .As<IFileReader>();                               
     builder.RegisterOptions<RmqMessageHandlerOptions>(config, sectionName, name);
     builder.RegisterType<RmqMessageHandler>()
         .As<IRmqMessageHandler>()
         .SingleInstance()
         .PropertiesAutowired();
     return builder;
 }
 
   public static ContainerBuilder RegisterEmailNotificationServiceOptions(this ContainerBuilder builder,
     IConfiguration config,
     string sectionName,
     string name = null)
  {
      builder.RegisterOptions<EmailNotificationServiceOptions>(config, sectionName, name);

      builder.RegisterType<EmailNotificationService>()
          .As<IEmailNotificationService>()
          .SingleInstance()
          .PropertiesAutowired();
      return builder;
  }
  }

可能的原因
  • 异常被静默吞噬:Main方法的catch块为空,容器构建、服务启动过程中若发生异常,会被完全隐藏,导致RunAsync无法正常启动但无报错信息。建议在catch块添加日志输出(如log.Fatal(e, "应用启动失败");),并重新抛出异常便于排查。
  • 静态字段线程安全问题:WindowsBackgroundService.WindowsServiceKey是静态字段,在配置读取后赋值,若存在多线程竞争(虽Main是单线程启动,但容器构建可能涉及异步操作),可能导致服务名称设置异常,引发Windows服务启动阻塞。可尝试硬编码服务名称测试,排除配置读取影响。
  • Autofac静态配置线程风险:AutofacConfiguration.Configuration为静态字段,在UseServiceProviderFactory中赋值,若容器构建过程中存在并发访问,可能导致配置值异常,进而影响服务注册。建议将配置作为参数传入BuildContainer,而非依赖静态字段。
  • 基础服务初始化阻塞:即使仅保留日志服务,NLog加载NLog.config时若遇到IO问题(如文件被占用、权限不足),可能导致初始化卡住。可临时移除NLog初始化,改用控制台日志测试是否能正常启动。
  • HostedService启动死锁:WindowsBackgroundService的StartAsync方法若存在同步阻塞操作(如无限循环等待资源、未正确使用异步API),会导致RunAsync挂起。需检查该服务的实现逻辑,确保异步方法无阻塞。

内容的提问来源于stack exchange,提问作者ravikiran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:43:11