4

Wcf サービス プロジェクトで Castle windsor 3.0 を使用しています。Topshelf を使用して Windows サービス プロジェクトとしてホストしています。私の wcf サービス構成はすべて app.config ファイルにあります。私は城の wcffacility を使用しており、このようなサービスを登録しています -

Container.AddFacility<WcfFacility>();
Container.AddFacility<LoggingFacility>(f => f.UseLog4Net());
container.Register(
            Classes
                .FromThisAssembly()
                .Pick()
                .If(x => x.IsClass 
                    && HasServiceContract(x))
                .WithServiceDefaultInterfaces()
                .Configure(c => c.AsWcfService().LifeStyle.HybridPerWcfOperationTransient()));

これにより、ILog (log4net から) が問題なくサービスに挿入されますが、IErrorHandler への挿入に失敗します。

IErrorHandler を使用して ServiceBehaviour を追加したので、ユーザーの未処理の例外をキャッチし、以下のコードを使用してエラーをログに記録できます。

 #region IErrorHandler Members
    public ILog Logger { get; set; }
    public bool HandleError(Exception error)
    {
        if (error is FaultException)
            return false; // Let WCF do normal processing

        return true; // Fault message is already generated
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {

        var uniqueKey = UniqueKeyGenerator.Generate();

        //create the custom wcfexception before passing that to client
        var wcfException = new CustomServerException("Unknown Error has occured. Please contact your administrator!", uniqueKey);

        //log the exception
        Logger.Error(uniqueKey, error);


        MessageFault messageFault = MessageFault.CreateFault(
            new FaultCode("Sender"),
            new FaultReason(wcfException.Message),
            wcfException,
            new NetDataContractSerializer());
        fault = Message.CreateMessage(version, messageFault, null);

    }

このstackoverflowの投稿を見ましたが、古すぎて回答が投稿されていなかったため、この新しい質問を投稿しています。

アップデート

私はgreyAlienによって提供された答えでこれを解決しました(今のところ部分的に)。私がしなければならなかったのは

  1. カスタム サービス動作クラスをウィンザー城に登録します。

    Container.Register(
             Component.For<IServiceBehavior>()
             .ImplementedBy<PassThroughExceptionHandlingBehaviour>()
                    .Named("IServiceBehavior")
    
  2. app.config ファイルから serviceBehaviour 拡張機能を削除します。構成ファイルに動作拡張を追加すると、何らかの理由で城が依存関係を注入できず、代わりに Wcf が新しいインスタンスを作成していて、ロガーのパブリック プロパティが null になっていると思います。

現在は機能していますが、behaviourextensions を使用して依存関係を注入する方法についても (将来) 理解する必要があります。

4

1 に答える 1

3

これは、あなたがやろうとしていると私が信じていることを行う自己ホスト型のサンプルです。コンソールアプリです。netsh で localhost:55001 を登録するには、Visual Studio を管理者として起動する必要があります。

キャッスル3.1を使用しています。

ソース コード ファイル:

namespace WcfSelfHost
{
using System;
using Castle.Windsor;
using Castle.Facilities.WcfIntegration;
using System.ServiceModel;
using Castle.MicroKernel.Registration;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using Castle.MicroKernel;

public interface ILog
{
    void LogMessage(string message);
}

public class ConsoleLogger : ILog
{
    public void LogMessage(string message)
    {
        Console.WriteLine(message);
    }
}

[ServiceBehavior]
public class CastleCreatedLoggingServiceBehavior : IServiceBehavior
{
    private readonly ILog logger;

    public CastleCreatedLoggingServiceBehavior(ILog logger)
    {
        this.logger = logger;
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
        this.logger.LogMessage("in AddBindingParameters");
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        this.logger.LogMessage("in ApplyDispatchBehavior");
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        this.logger.LogMessage("in Validate");
    }
}

[ServiceContract]
public interface IService
{
    [OperationContract]
    void TheOneOperation(string data);
}

public class ServiceImplementation : IService
{
    private readonly ILog logger;

    public ServiceImplementation(ILog logger)
    {
        this.logger = logger;
    }

    public void TheOneOperation(string data)
    {
        this.logger.LogMessage("service received message:");
        this.logger.LogMessage(data);
    }
}

public class ConsoleApplication
{
    public static void Main()
    {
        //making this a variable to show the requirement that the names match
        string serviceName = "TheService";

        //configure the container with all the items we need
        IWindsorContainer container = new WindsorContainer()
            .AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero)
            .Register(
                Component.For<CastleCreatedLoggingServiceBehavior>(),
                Component.For<ILog>()
                    .ImplementedBy<ConsoleLogger>()
                    .LifestyleSingleton(),
                Component.For<IService>()
                    .ImplementedBy<ServiceImplementation>()
                    .LifestyleSingleton()
                    .Named(serviceName)
            );

        //setup our factory with that has knowledge of our kernel.
        DefaultServiceHostFactory factory = new DefaultServiceHostFactory(container.Kernel);

        //create a host for our service matching the name of the castle component.  Not adding any additional base addresses.
        using (ServiceHostBase host = factory.CreateServiceHost(serviceName, new Uri[0]))
        {
            host.Open();
            Console.WriteLine("server listening for messages");


            //and here's the client..
            IWindsorContainer clientContainer = new WindsorContainer()
                .AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero)
                .Register(
                    Component.For<IService>()
                        .AsWcfClient(WcfEndpoint.FromConfiguration("serviceEndpointDefinition"))
                );

            IService client = clientContainer.Resolve<IService>();
            client.TheOneOperation("data from client");
            Console.ReadLine();

        }
    }
}
}

コンソール アプリケーションの app.config ファイルは次のとおりです。流暢な API を使用してソース コードでこれらすべてを構成することもできましたが、サービスとクライアント構成を分離するのはごく普通のことなので、構成ファイル ルートを選択しました。ac# 流暢な API バージョンが必要な場合はお知らせください。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="overrideMessageSize_forBasicHttpBinding" maxBufferPoolSize="2147483647"
             maxReceivedMessageSize="2147483647"/>
  </basicHttpBinding>
</bindings>

<services>
  <service name="WcfSelfHost.ServiceImplementation">
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:55001/baseaddress"/>
      </baseAddresses>
    </host>

    <endpoint 
        contract="WcfSelfHost.IService"
        binding="basicHttpBinding"
        bindingConfiguration="overrideMessageSize_forBasicHttpBinding" 
        address="http://localhost:55001/baseaddress/serviceimplementation"
        />
  </service>
</services>

    <client>
        <endpoint 
    name="serviceEndpointDefinition"
    contract="WcfSelfHost.IService" 
    binding="basicHttpBinding" 
    bindingConfiguration="overrideMessageSize_forBasicHttpBinding"
    address="http://localhost:55001/baseaddress/serviceimplementation"
    />
    </client>

</system.serviceModel>
</configuration>
于 2013-10-29T07:03:04.323 に答える