WPF集成SimpleInjector时HttpClient.GetAsync调用挂起问题求助
问题根源:异步操作阻塞导致的死锁
你的问题是典型的WPF UI线程死锁,原因在于:
- WPF的UI线程带有
SynchronizationContext,异步方法中await会捕获这个上下文,任务完成后试图回到UI线程继续执行。 - 你在
SetupService的构造函数中调用RefreshSetup,里面用.Result阻塞了UI线程等待异步任务;但await client.GetAsync(endpoint)需要回到被阻塞的UI线程,导致双方互相等待,形成死锁。
解决办法(保留SimpleInjector机制)
核心思路:把异步初始化逻辑从构造函数移到独立的异步方法中,避免在UI线程中阻塞等待异步任务。
1. 修改SetupService,拆分异步初始化逻辑
移除构造函数中的RefreshSetup调用,新增异步初始化方法,用await替代.Result:
public class SetupService: ISetupService { private static readonly Dictionary<string, string> AcceptType = new Dictionary<string, string> { {"Accept", "application/xml"} }; private const string AuthenticationType = "Basic"; private readonly IServiceClient _serviceClient; private readonly ILoggingProvider _logger; private readonly IConfigurationSection _configuration; private SetupResponse _response; // 构造函数仅做依赖注入,不执行异步逻辑 public SetupService(IConfigurationSection configuration, IServiceClient serviceClient, ILoggingProvider logger) { _serviceClient = serviceClient; _logger = logger; _configuration = configuration; } // 异步初始化方法 public async Task InitAsync() { try { var token = BuildIdentityToken(); var authHeaderClear = string.Format("IDENTITY_TOKEN:{0}", token); var authenticationHeaderValue = new AuthenticationHeaderValue(AuthenticationType, Convert.ToBase64String(Encoding.ASCII.GetBytes(authHeaderClear))); _serviceClient.Url = _configuration.Url; // 用await替代.Result,避免阻塞 var httpResponse = await _serviceClient.GetAsync(string.Empty, authenticationHeaderValue, AcceptType); var responseString = await httpResponse.Content.ReadAsStringAsync(); _response = responseString.FromXML<SetupResponse>(); } catch (Exception e) { _logger?.LogError(e, "初始化Setup失败"); throw; } } // 保留手动刷新的异步方法(如果需要) public async Task RefreshSetupAsync() { await InitAsync(); } }
2. 修改App.xaml.cs,异步执行初始化
将OnStartup改为异步方法,注册依赖后手动调用SetupService的异步初始化:
public partial class App : Application { private static readonly Container _container = new Container(); // 事件处理方法允许使用async void protected override async void OnStartup(StartupEventArgs e) { base.OnStartup(e); RegisterDependencies(); _container.Verify(); // 获取SetupService实例并执行异步初始化 var setupService = _container.GetInstance<ISetupService>(); await setupService.InitAsync(); } private void RegisterDependencies() { var serviceConfigSection = ServiceConfigurationSection.Get(); _container.RegisterSingle<ILoggingProvider, LoggingProvider>(); _container.RegisterSingle<IServiceClient>(() => new ServiceClient(_container.GetInstance<ILoggingProvider>())); _container.RegisterSingle<IConfigurationSection>(() => SetupConfigurationSection.Get()); _container.RegisterSingle<ISetupService, SetupService>(); } }
3. 额外优化建议
- 复用HttpClient实例:当前
ServiceClient每次创建新的HttpClient,建议将HttpClient注册为Singleton注入到ServiceClient中,避免Socket连接耗尽问题。 - 禁止构造函数执行异步/阻塞操作:构造函数仅负责依赖赋值,复杂初始化(尤其是IO、异步操作)必须放到专门的方法中,这是依赖注入的通用最佳实践。
内容的提问来源于stack exchange,提问作者Andrew Humphries
相关产品推荐
相关产品推荐

