10

IErrorHandlerWCF サービスのすべてのエラー処理を 1 か所に集中させるために実装しています。これはかなりうまくいきます:

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、フィルターのようにインジェクションを許可するように設定しようとしましたが、うまくいかないようでした。これを実現する方法はありますか?

4

1 に答える 1

6

IErrorHandler遅い答えですが、カスタムを作成することで依存関係を注入できServiceHostますTestServiceHost

あなたTestServiceHostがする必要がある:

  1. パラメータを指定してコンストラクタを実装しIErrorHandlerます。
  2. 内部で、* という名前のネストされたプライベート クラスを作成します。ErrorHandlerBehaviourこれは、 と の両方を実装する必要がIServiceBehaviorありますIErrorHandlerIErrorHandlerまた、パラメーターを持つコンストラクターも必要です。
  3. サービスの動作OnStarting()に追加するメソッドをオーバーライドします。ErrorHandlerBehaviourすべての動作は の前に追加する必要がありますbase.OnStarting()

*アイデアは、本の「Programming WCF Services」のJuval Lowyの例から生まれました。そこにあるフォールトとエラー拡張機能の詳細については、こちらを参照してください。

これは、動作中のホスト コンソール アプリケーションです。そこでは 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したことを確認してください

于 2015-12-21T12:34:05.483 に答える