如何用WebApplicationFactory测试带Autofac DI的CoreWCF端点?
优化CoreWCF集成测试中TestServer的IServerAddressesFeature配置(替代反射方案)
问题背景
使用Autofac作为DI容器的CoreWCF项目,通过自定义WebApplicationFactory编写集成测试时,发现TestServer未配置IServerAddressesFeature,导致CoreWCF的ApplyConfiguration执行失败。当前通过反射修改TestServer的私有字段解决,但依赖内部实现,稳定性不足。
更优解决方案
利用TestServer公开的Features属性直接配置IServerAddressesFeature,无需反射。具体修改WcfWebApplicationFactory的CreateHost方法,在Host创建完成后直接操作TestServer的特性集合:
优化后的完整代码
/// Enables in-memory integration testing for CoreWCF (outside-in testing via <see cref="HttpClient"/>). /// /// Use these tests to exercise the entire HTTP stack, rather than create in-process ServiceModel channels. /// </summary> /// <typeparam name="TStartup"></typeparam> public class WcfWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class { private ILifetimeScope _container; protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureTestContainer<ContainerBuilder>(container => { container.RegisterBuildCallback(BuildCallback); }); } private void BuildCallback(ILifetimeScope obj) { _container = obj; } protected override IHost CreateHost(IHostBuilder builder) { builder.UseServiceProviderFactory(new CustomServiceProviderFactory()); var host = base.CreateHost(builder); // 配置TestServer的IServerAddressesFeature,无需反射 var testServer = host.Services.GetRequiredService<IServer>() as TestServer; if (testServer != null) { var addressesFeature = testServer.Features.Get<IServerAddressesFeature>() ?? new ServerAddressesFeature(); addressesFeature.Addresses.Add(ClientOptions.BaseAddress.ToString()); testServer.Features.Set(addressesFeature); } return host; } } /// <summary> /// Handles Autofac container integration with ASP.NET Core test pipeline /// </summary> public class CustomServiceProviderFactory : IServiceProviderFactory<ContainerBuilder> { private readonly AutofacServiceProviderFactory _wrapped = new AutofacServiceProviderFactory(); private IServiceCollection _services; public ContainerBuilder CreateBuilder(IServiceCollection services) { _services = services; return _wrapped.CreateBuilder(services); } public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder) { var sp = _services.BuildServiceProvider(); #pragma warning disable CS0612 // Type or member is obsolete var filters = sp.GetRequiredService<IEnumerable<IStartupConfigureContainerFilter<ContainerBuilder>>>(); #pragma warning restore CS0612 // Type or member is obsolete foreach (var filter in filters) { filter.ConfigureContainer(b => { })(containerBuilder); } return _wrapped.CreateServiceProvider(containerBuilder); } }
方案优势
- 避免反射依赖:不再依赖
TestServer的私有字段,利用公开API操作,代码稳定性更高,不会因框架内部实现变更而失效。 - 逻辑更清晰:将特性配置逻辑放在
CreateHost阶段,符合WebApplicationFactory的生命周期流程,代码可读性更强。 - 职责更单一:移除原代码中反射相关的复杂逻辑,
CustomServiceProviderFactory仅专注于Autofac容器与ASP.NET Core测试管道的集成。
内容的提问来源于stack exchange,提问作者Guy Pender
相关产品推荐
相关产品推荐

