wcf - 将依赖项注入(inject) IErrorHandler 实现

标签 wcf ninject ierrorhandler

我正在实现 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 在服务的其余部分注入(inject)依赖项,我也想在这里做同样的事情。由于 WCF 正在根据我的配置构造对象,并且我认为我在此过程中没有任何 Hook ,因此我需要使用属性注入(inject):
    [Inject]
    public ILoggingService Logger { get; set; }

然而,这似乎永远不会被注入(inject)。我尝试使用 Ninject 的 MVC 扩展来设置 ServiceErrorHandler允许像过滤器一样注入(inject),但这似乎没有奏效。有没有办法做到这一点?

最佳答案

迟到的答案,但您可以将依赖项注入(inject) IErrorHandler通过创建您的自定义 ServiceHost ,假设 TestServiceHost .

在您的 TestServiceHost你需要做:

  • 使用 IErrorHandler 实现构造函数范围。
  • 在内部,创建一个名为 ErrorHandlerBehaviour 的私有(private)嵌套类*,需要同时实现IServiceBehaviorIErrorHandler .它还必须有带有 IErrorHandler 的构造函数范围。
  • 覆盖 OnStarting()方法,您将在其中添加 ErrorHandlerBehaviour服务行为。所有行为必须在base.OnStarting()之前添加.

  • *这个想法来自 Juval Lowy 在“Programming WCF Services”一书中的示例。您可以在此处找到有关故障和错误扩展的更多信息。

    这是工作主机控制台应用程序。我不在那里使用 IoC,只是 Pure DI ,但您可以使用任何您想要的 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.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给你的引用

    关于wcf - 将依赖项注入(inject) IErrorHandler 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18113345/

    相关文章:

    c# - 我已经创建了一个 WCF 服务,现在我想从引用中调用它,但为什么会出现 InvalidOperationException?

    注入(inject)拦截

    c# - 洋葱架构日志记录 NHibernate

    json - 如何从 Lua 中的第三方库捕获错误消息?

    c# - 将多个命名空间添加到 MessageContract WCF 响应对象 (MessageBodyMember)

    java - IWAB0399E 从 WSDL 生成 Java 时出错 : java. io.IOException:错误:缺少 <soap:fault> 元素 inFault

    c# - 如何同时(并行)使用多个客户端调用 WCF webservice

    c# - 设置 ninject 比较规则 I +"Somevalue"= Somevalue

    asp.net - 需要方法的参数值,其中在每个方法中没有特定代码的情况下会引发异常以进行日志记录

    wcf - IErrorHandler 未被绑定(bind),且未处理错误