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

自托管环境下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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 12:17:52