Castle Windsor - 将记录器注入IErrorHandler

时间:2013-10-28 10:41:36

标签: wcf c#-4.0 castle-windsor ierrorhandler

在我的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 post,但它太旧了,没有回复帖子所以发布了这个新问题。

更新

我通过greyAlien提供的答案得到了解决(部分暂时解决)。 我所要做的只是

  1. 将自定义servicebehavior类注册到城堡windsor。

    Container.Register(
             Component.For<IServiceBehavior>()
             .ImplementedBy<PassThroughExceptionHandlingBehaviour>()
                    .Named("IServiceBehavior")
    
  2. 从app.config文件中删除serviceBehaviour扩展名。当我添加     配置文件中的行为扩展,由于某种原因,城堡不是     能够注入依赖项我认为Wcf正在创建新的     实例和记录器公共属性结果为空。

  3. 它现在适用于我,但需要了解(以后)如何使用behaviourextensions注入依赖项。

1 个答案:

答案 0 :(得分:3)

这是一个自我托管的示例,可以完成我认为您正在尝试的事情。这是一个控制台应用程序。您需要以管理员身份启动visual studio才能让netsh注册localhost:55001

我正在使用城堡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在源代码中配置所有这些,但是将服务和服务分开。客户端配置很正常,所以我选择了配置文件路由。如果你想要一个c#流畅的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>