如何在多项目结构的WCF应用中添加IoC注册启动类?
嘿,我来帮你搞定这个WCF里IoC容器注册的难题!你遇到的问题核心在于:WCF的服务生命周期和ASP.NET的启动管道并不是完全绑定的,所以直接用Startup或Global.asax的常规ASP.NET初始化逻辑,没法直接影响WCF服务的实例创建过程。下面给你几个可行的解决方案,按推荐程度排序:
方案一:自定义ServiceHostFactory(推荐)
这是WCF集成IoC的标准做法,直接接管ServiceHost的创建流程,在里面初始化IoC容器并配置服务实例的创建逻辑。
步骤1:在Service.WCFApplication中创建自定义Factory
using Autofac; // 这里以Autofac为例,你可以换成自己用的IoC容器 using Autofac.Integration.Wcf; using System.ServiceModel; using System.ServiceModel.Activation; namespace Service.WCFApplication { public class CustomServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { // 1. 初始化IoC容器,注册业务逻辑和服务类 var containerBuilder = new ContainerBuilder(); // 注册你的业务逻辑接口和实现 containerBuilder.RegisterType<Domain.BusinessLogic>().As<IDomainBusinessLogic>(); // 注册WCF服务类,让容器管理实例生命周期 containerBuilder.RegisterType<Service.WCFLibrary.MainService>(); var container = containerBuilder.Build(); // 2. 创建ServiceHost并注入容器依赖 var serviceHost = new ServiceHost(serviceType, baseAddresses); // 添加Autofac的WCF集成行为(不同容器有对应的集成组件) serviceHost.Description.Behaviors.Add(new AutofacDependencyInjectionBehavior(container)); return serviceHost; } } }
步骤2:修改MainService.svc的指令,指定自定义Factory
把原来的ServiceHost指令改成下面这样,指定我们刚创建的Factory:
<%@ ServiceHost Language="C#" Debug="true" Service="Service.WCFLibrary.MainService" Factory="Service.WCFApplication.CustomServiceHostFactory" %>
这样每次WCF服务启动时,都会通过我们的Factory创建ServiceHost,IoC容器也会在此时初始化,服务实例的依赖会被自动注入。
方案二:利用InstanceContextInitializer(需ASP.NET兼容模式)
如果你想借助Global.asax的启动逻辑,可以开启WCF的ASP.NET兼容模式,然后通过InstanceContextInitializer来注入依赖。
步骤1:开启ASP.NET兼容模式
在Service.WCFApplication的web.config中添加配置:
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> </system.serviceModel>
步骤2:在Global.asax中初始化容器并注册Initializer
using Autofac; using System.ServiceModel; using System.ServiceModel.Description; namespace Service.WCFApplication { public class Global : HttpApplication { protected void Application_Start(object sender, EventArgs e) { // 初始化IoC容器 var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Domain.BusinessLogic>().As<IDomainBusinessLogic>(); var container = containerBuilder.Build(); // 给所有WCF服务添加InstanceContextInitializer foreach (var serviceHost in ServiceHostBase.Applications.SelectMany(app => app.ServiceHosts)) { var behavior = serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>() ?? new ServiceBehaviorAttribute(); behavior.InstanceContextInitializers.Add(new IoCInstanceContextInitializer(container)); serviceHost.Description.Behaviors.Add(behavior); } } } // 自定义InstanceContextInitializer public class IoCInstanceContextInitializer : IInstanceContextInitializer { private readonly IContainer _container; public IoCInstanceContextInitializer(IContainer container) { _container = container; } public void Initialize(InstanceContext instanceContext, Message message) { // 设置自定义实例提供器,让IoC容器创建服务实例 instanceContext.Extensions.Add(new IoCInstanceProviderExtension(_container, instanceContext.Host.Description.ServiceType)); } } // 辅助扩展类,用于挂载实例提供器 public class IoCInstanceProviderExtension : IExtension<InstanceContext> { private readonly IInstanceProvider _instanceProvider; public IoCInstanceProviderExtension(IContainer container, Type serviceType) { _instanceProvider = new AutofacInstanceProvider(container, serviceType); } public void Attach(InstanceContext owner) { owner.InstanceProvider = _instanceProvider; } public void Detach(InstanceContext owner) { } } }
方案三:构造函数直接解析(应急用,不推荐)
如果只是临时测试,不想搞复杂的配置,可以在Global.asax初始化容器并保存为静态变量,然后在服务构造函数里直接解析依赖。这种方法耦合度高,不建议用于生产环境:
步骤1:在Global.asax初始化容器
using Autofac; namespace Service.WCFApplication { public class Global : HttpApplication { public static IContainer AppContainer { get; private set; } protected void Application_Start(object sender, EventArgs e) { var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Domain.BusinessLogic>().As<IDomainBusinessLogic>(); AppContainer = containerBuilder.Build(); } } }
步骤2:在MainService中解析依赖
public class MainService : IMainService { private readonly IDomainBusinessLogic _businessLogic; public MainService() { // 直接从静态容器解析 _businessLogic = Service.WCFApplication.Global.AppContainer.Resolve<IDomainBusinessLogic>(); } public GetTestResponse GetTest(GetTestRequest request) { // 使用业务逻辑处理请求 return _businessLogic.HandleTestRequest(request); } }
总结
最推荐的是方案一,它不需要依赖ASP.NET兼容模式,完全遵循WCF的扩展机制,代码耦合度低,也是社区通用的做法。如果你用的是其他IoC容器(比如Unity、Ninject),只需要替换对应的集成组件即可,核心思路都是通过自定义ServiceHostFactory来控制服务实例的创建。
内容的提问来源于stack exchange,提问作者cSteusloff

