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

更新

我用 grayAlien 提供的答案解决了这个问题(部分暂时)。我所要做的就是

  1. 将自定义服务行为类注册到城堡温莎。

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

它现在对我有用,但需要了解(将来)如何使用行为扩展来注入依赖项。

4

1 回答 1

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 文件。我们本可以在源代码中使用 fluent API 来配置所有这些,但是将服务和客户端配置分开是很正常的,所以我选择了配置文件路径。如果您想要 ac# fluent 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 回答