Wcf 将依赖项注入IErrorHandler实现

Wcf 将依赖项注入IErrorHandler实现,wcf,ninject,ierrorhandler,Wcf,Ninject,Ierrorhandler,我正在实现IErrorHandler,以便将我的WCF服务的所有错误处理集中在一个地方。这样做效果相当好: public class ServiceErrorHandler : IErrorHandler { public bool HandleError(Exception error) { // ..Log.. } public void ProvideFault(Exception error, MessageVersion versio

我正在实现
IErrorHandler
,以便将我的WCF服务的所有错误处理集中在一个地方。这样做效果相当好:

public class ServiceErrorHandler : IErrorHandler
{

    public bool HandleError(Exception error)
    {
        // ..Log..
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        // ..Provide fault..
    }

}
现在,我们使用Ninject在服务的其余部分注入依赖项,我也希望在这里这样做。由于WCF是基于我的配置构建对象的,并且我认为我在这个过程中没有任何挂钩,所以我需要使用属性注入:

    [Inject]
    public ILoggingService Logger { get; set; }

然而,这似乎从未被注入。我尝试使用Ninject的MVC扩展来设置
ServiceErrorHandler
以允许像过滤器一样的注入,但这似乎没有奏效。有什么方法可以实现这一点吗?

请稍后回答,但您可以通过创建自定义的
ServiceHost
(比如
TestServiceHost
)将依赖项注入
IErrorHandler

TestServiceHost
中,您需要执行以下操作:

  • 使用
    IErrorHandler
    参数实现构造函数
  • 在内部,创建一个名为
    errorHandlerBehavior
    *的私有嵌套类,该类需要实现
    IServiceBehavior
    IErrorHandler
    。它还必须具有带有
    IErrorHandler
    参数的构造函数
  • 重写
    OnStarting()
    方法,您将在其中向服务行为添加
    ErrorHandlerBehavior
    。必须在
    base.onStart()之前添加所有行为
  • *这个想法来源于Juval Lowy在《编写WCF服务程序》一书中的例子。有关故障和错误扩展的更多信息,您可以在此处找到

    下面是正在工作的主机控制台应用程序。我在这里不使用IoC,只是,但是您可以轻松地使用您想要的任何IoC解决记录器问题:

    using System;
    using System.Collections.ObjectModel;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace ConsoleHost
    {
        class Program
        {
            static void Main(string[] args)
            {
                var logger = new DummyLogger();
                var errorHandler = new TestErrorHandler(logger);
    
                ServiceHost host = new TestServiceHost(errorHandler, typeof(TestService), new Uri("net.tcp://localhost:8002"));
                host.Open();
    
                Console.WriteLine("Press enter to exit");
                Console.ReadKey();
            }
        }
    
        [ServiceContract]
        public interface ITestService
        {
            [OperationContract]
            string Test(int input);
        }
    
        public class TestService : ITestService
        {
            public string Test(int input)
            {
                throw new Exception("Test exception!");
            }
        }
    
        public class TestErrorHandler : IErrorHandler
        {
            private ILogger Logger { get; }
    
            public TestErrorHandler(ILogger logger)
            {
                Logger = logger;
            }
    
            public bool HandleError(Exception error)
            {
                Logger.Log(error.Message);
                return true;
            }
    
            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {
                FaultException fe = new FaultException();
                MessageFault message = fe.CreateMessageFault();
                fault = Message.CreateMessage(version, message, null);
            }
        }
    
        public class TestServiceHost : ServiceHost
        {
            private readonly IErrorHandler errorHandler;
    
            public TestServiceHost(IErrorHandler errorHandler, Type serviceType, params Uri[] baseAddresses)
                : base(serviceType, baseAddresses)
            {
                this.errorHandler = errorHandler;
            }
    
            protected override void OnOpening()
            {
                Description.Behaviors.Add(new ErrorHandlerBehaviour(errorHandler));
                base.OnOpening();
            }
    
            class ErrorHandlerBehaviour : IServiceBehavior, IErrorHandler
            {
                private readonly IErrorHandler errorHandler;
    
                public ErrorHandlerBehaviour(IErrorHandler errorHandler)
                {
                    this.errorHandler = errorHandler;
                }
    
                bool IErrorHandler.HandleError(Exception error)
                {
                    return errorHandler.HandleError(error);
                }
    
                void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
                {
                    errorHandler.ProvideFault(error, version, ref fault);
                }
    
                void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
                {
                    foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
                    {
                        channelDispatcher.ErrorHandlers.Add(this);
                    }
                }
    
                void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
                {
                }
    
                void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
                {
                }
            }
        }
    
        // Dummy logger
        public interface ILogger
        {
            void Log(string input);
        }
    
        public class DummyLogger : ILogger
        {
            public void Log(string input) => Console.WriteLine(input);
        }
    }
    
    使用系统;
    使用System.Collections.ObjectModel;
    使用System.ServiceModel;
    使用System.ServiceModel.Channel;
    使用System.ServiceModel.Description;
    使用System.ServiceModel.Dispatcher;
    名称空间控制台主机
    {
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    变量记录器=新的DummyLogger();
    var errorHandler=新的TestErrorHandler(记录器);
    ServiceHost主机=新的TestServiceHost(errorHandler,typeof(TestService)),新的Uri(“net。tcp://localhost:8002"));
    host.Open();
    控制台写入线(“按回车键退出”);
    Console.ReadKey();
    }
    }
    [服务合同]
    公共接口ITestService
    {
    [经营合同]
    字符串测试(int输入);
    }
    公共类TestService:ITestService
    {
    公共字符串测试(int输入)
    {
    抛出新异常(“测试异常!”);
    }
    }
    公共类TestErrorHandler:IErrorHandler
    {
    专用ILogger记录器{get;}
    公共测试仪指针(ILogger记录器)
    {
    记录器=记录器;
    }
    公共布尔句柄错误(异常错误)
    {
    Logger.Log(错误消息);
    返回true;
    }
    public void providefaulture(异常错误,消息版本,ref消息错误)
    {
    FaultException fe=新的FaultException();
    MessageFault message=fe.CreateMessageFault();
    fault=Message.CreateMessage(版本,消息,空);
    }
    }
    公共类TestServiceHost:ServiceHost
    {
    私有只读IErrorHandler errorHandler;
    公共TestServiceHost(IErrorHandler errorHandler,类型serviceType,参数Uri[]基地址)
    :base(服务类型、基本地址)
    {
    this.errorHandler=errorHandler;
    }
    受保护的覆盖无效打开()
    {
    Description.Behaviors.Add(新的ErrorHandlerBehavior(errorHandler));
    base.OnOpening();
    }
    类ErrorHandlerBehavior:IServiceBehavior,IErrorHandler
    {
    私有只读IErrorHandler errorHandler;
    公共errorHandler行为(IErrorHandler errorHandler)
    {
    this.errorHandler=errorHandler;
    }
    bool IErrorHandler.HandleError(异常错误)
    {
    返回errorHandler.HandleError(错误);
    }
    void IErrorHandler.providDefault(异常错误、MessageVersion版本、ref消息错误)
    {
    errorHandler.ProviderDefault(错误、版本、参考故障);
    }
    无效IServiceBehavior.ApplyDispatchBehavior(ServiceDescription ServiceDescription,ServiceHostBase ServiceHostBase)
    {
    foreach(serviceHostBase.ChannelDispatchers中的ChannelDispatcher ChannelDispatcher)
    {
    channelDispatcher.ErrorHandlers.Add(此);
    }
    }
    void IServiceBehavior.AddBindingParameters(ServiceDescription ServiceDescription,ServiceHostBase ServiceHostBase,集合终结点,BindingParameterCollection bindingParameters)
    {
    }
    无效IServiceBehavior.Validate(ServiceDescription ServiceDescription,ServiceHostBase ServiceHostBase)
    {
    }
    }
    }
    //虚拟记录器
    公共接口ILogger
    {
    无效日志(字符串输入);
    }
    公共类DummyLogger:ILogger
    {
    公共作废日志(字符串输入)=>Console.WriteLine(输入);
    }
    }
    
    和配置:

    <system.serviceModel>
      <services>
        <service name="ConsoleHost.TestService">
          <endpoint address="net.tcp://localhost:8002/TestService"
                    binding="netTcpBinding"
                    contract="ConsoleHost.ITestService" />
        </service>
      </services>
    </system.serviceModel>
    
    
    

    顺便说一句。确保您在引用中添加了
    System.Runtime.Serialization

    您也使用了Ninject WCF扩展吗?@DanielMarbach:我有WCF扩展,但我看不到其中有任何东西对这种情况有帮助。有什么我可以用的吗?@zimdanen你解决这个问题了吗?最好是在没有国际奥委会的情况下注入ILogger,但使用纯。。。纯DI。只需在您的
    ServiceErrorHandler
    @Marshall中插入一个接口ILogger即可。马歇尔:我们是usi