【问题标题】:Injecting dependencies into an IErrorHandler implementation将依赖项注入 IErrorHandler 实现
【发布时间】:2013-08-07 20:37:42
【问题描述】:

我正在实施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 以允许像过滤器一样进行注入,但这似乎没有奏效。有没有办法做到这一点?

【问题讨论】:

  • 你也使用 Ninject WCF 扩展吗?
  • @DanielMarbach:我有 WCF 扩展,但在这种情况下我看不到任何有用的东西。有什么我可以用的吗?
  • @zimdanen 你解决了这个问题吗?最好的办法是在没有 IoC 的情况下注入 ILogger,但使用纯...纯 DI。只需在 ServiceErrorHandler 中注入接口 ILogger
  • @Marshall:我们现在正在使用服务定位器模式。
  • @zimdanen 感谢您的回答。所以你只是在 HandleError 中使用一个全局静态类? (你知道这是一种反模式吗?)

标签: wcf ninject ierrorhandler


【解决方案1】:

迟到的答案,但您可以通过创建自定义ServiceHost 将依赖项注入IErrorHandler,比如说TestServiceHost

在您的TestServiceHost 中您需要这样做:

  1. 使用IErrorHandler 参数实现构造函数。
  2. 在里面,创建一个名为ErrorHandlerBehaviour*的私有嵌套类,它需要同时实现IServiceBehaviorIErrorHandler。它还必须有带有IErrorHandler 参数的构造函数。
  3. 覆盖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 添加到您的参考文献中

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 2011-05-06
    • 2015-06-25
    • 2023-03-14
    相关资源
    最近更新 更多