自托管环境下WCF REST服务集成SimpleInjector依赖注入的问题
解决WCF REST(WebServiceHost)与SimpleInjector集成的地址过滤器不匹配问题
你遇到的AddressFilter不匹配错误,本质是因为用针对传统WCF ServiceHost设计的SimpleInjectorServiceHost来搭建REST服务时,端点配置和WebServiceHost的自动配置逻辑冲突了。WebServiceHost会自动为REST服务创建适配的端点和行为,手动添加端点反而会导致地址匹配异常。
下面是适配WebServiceHost的SimpleInjector集成方案,核心是自定义WebServiceHost工厂,让SimpleInjector接管服务实例的创建:
1. 修正依赖注入配置(Bootstrapper)
保留基础DI配置,但无需调用RegisterWcfServices(该方法针对传统ServiceHost),改为手动注册服务类型:
using System.Reflection; using SimpleInjector; namespace AAARestService { public static class BootStrapper { public static readonly Container Container; static BootStrapper() { Container = new Container(); // 注册业务依赖项 Container.Register<IMyDateTimeService, MyDateTimeService>(Lifestyle.Singleton); // 注册WCF REST服务类,使用Scoped生命周期对应WCF请求级实例 Container.Register<AAADispPushBatchService>(Lifestyle.Scoped); // 验证容器配置,提前发现依赖问题 Container.Verify(); } } }
2. 自定义WebServiceHost工厂
创建继承自WebServiceHostFactory的工厂类,重写实例创建逻辑,让SimpleInjector提供服务实例:
using System; using System.ServiceModel; using System.ServiceModel.Activation; using SimpleInjector; namespace AAARestService { public class SimpleInjectorWebServiceHostFactory : WebServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { // 用WebServiceHost原生逻辑初始化,它会自动配置REST端点 var host = new WebServiceHost(serviceType, baseAddresses); // 替换默认实例提供器为SimpleInjector的实现 host.Description.Behaviors.Remove(typeof(ServiceBehaviorAttribute)); host.Description.Behaviors.Add(new SimpleInjectorServiceBehavior(BootStrapper.Container)); return host; } // 自定义ServiceBehavior,绑定SimpleInjector容器 private class SimpleInjectorServiceBehavior : ServiceBehaviorAttribute { private readonly Container _container; public SimpleInjectorServiceBehavior(Container container) { _container = container; } public override IInstanceProvider GetInstanceProvider(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { return new SimpleInjectorInstanceProvider(_container, serviceDescription.ServiceType); } } // 自定义实例提供器,从容器获取服务实例 private class SimpleInjectorInstanceProvider : IInstanceProvider { private readonly Container _container; private readonly Type _serviceType; public SimpleInjectorInstanceProvider(Container container, Type serviceType) { _container = container; _serviceType = serviceType; } public object GetInstance(InstanceContext instanceContext, Message message) { return _container.GetInstance(_serviceType); } public object GetInstance(InstanceContext instanceContext) { return GetInstance(instanceContext, null); } public void ReleaseInstance(InstanceContext instanceContext, object instance) { // Scoped生命周期由容器自动管理,无需手动释放 } } } }
3. 修正服务启动逻辑(Main方法)
直接用自定义工厂创建WebServiceHost,无需手动添加端点(WebServiceHost会自动处理REST配置):
static void Main(string[] args) { try { Uri httpUrl = new Uri("http://localhost:8733/3AdispPushBatchService"); SimpleInjectorWebServiceHostFactory factory = new SimpleInjectorWebServiceHostFactory(); var webHost = factory.CreateServiceHost(typeof(AAADispPushBatchService), new[] { httpUrl }); // 可选:添加元数据行为,支持HTTP获取WSDL ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; webHost.Description.Behaviors.Add(smb); webHost.Open(); foreach (ServiceEndpoint se in webHost.Description.Endpoints) Console.WriteLine("Service is hosted with endpoint: " + se.Address); Console.WriteLine("Host is running... Press <Enter> key to stop"); Console.ReadLine(); webHost.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.InnerException?.Message); Console.ReadLine(); } }
4. 服务类支持构造函数注入
修改服务实现类,通过构造函数接收依赖(以IMyDateTimeService为例):
using System; using System.Configuration; using System.IO; using System.ServiceModel.Activation; using System.Text; using Newtonsoft.Json; namespace AAARestService { [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class AAADispPushBatchService : IAaaDispPushBatchService { private readonly IMyDateTimeService _dateTimeService; // 构造函数注入依赖 public AAADispPushBatchService(IMyDateTimeService dateTimeService) { _dateTimeService = dateTimeService; } public string GetBatchJson(Stream jsonFileContent) { // 原有业务逻辑保持不变,可按需使用_dateTimeService try { var sr = new StreamReader(jsonFileContent, Encoding.UTF8); var str = sr.ReadToEnd(); if (String.IsNullOrWhiteSpace(str)) throw new ArgumentException("No data inside body request"); var definition = new { BatchName = "" }; var json = JsonConvert.DeserializeAnonymousType(str, definition); if (json == null) throw new ArgumentException("No valid json inside"); if (String.IsNullOrWhiteSpace(json.BatchName)) throw new ArgumentException("BatchName not present"); var currentDir = ConfigurationManager.AppSettings["BatchPath"]; Directory.CreateDirectory(currentDir); var filepath = Path.Combine(currentDir, json.BatchName+".json"); File.WriteAllText(filepath, str); return $"Saved in {filepath} at {_dateTimeService.GetCurrentTime()}"; } catch (Exception e) { return e.Message; } } } }
关键说明
- 放弃
SimpleInjectorServiceHost,改用WebServiceHost原生逻辑,它会自动配置WebHttpBinding和WebHttpBehavior,避免手动配置的冲突。 - 通过自定义
IInstanceProvider让SimpleInjector接管服务实例创建,完美实现依赖注入。 - 服务类使用
Scoped生命周期,对应WCF的每个请求实例,符合REST服务的使用场景。
内容的提问来源于stack exchange,提问作者Federico Borghesi
相关产品推荐
相关产品推荐

