简体   繁体   English

具有Autofac注入的WCF通用错误处理程序

[英]WCF Generic Error Handler with Autofac Injection

I am trying to implement a simple generic error handler in my wcf project but the catch is that i want to inject a service (using autofac) in order to save all exceptions. 我正在尝试在wcf项目中实现一个简单的通用错误处理程序,但要注意的是我想注入一个服务(使用autofac)以保存所有异常。 I ve looked everywhere and I didn't find anything. 我到处都看过,什么也没找到。 I am using Autofac with Autofac.Integration.Wcf. 我正在将Autofac与Autofac.Integration.Wcf一起使用。

public class GlobalErrorHandler : IErrorHandler
{

    private IErrorService ErrorService;

    public GlobalErrorHandler(IErrorService errorService)
    {
        this.ErrorService = errorService;
    }

    public bool HandleError(Exception error)
    {
        return true;
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        //log the error using the service
    }
}

public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{

    public override Type BehaviorType
    {
        get { return GetType(); }
    }

    protected override object CreateBehavior()
    {
        return this;
    }

    private IErrorHandler GetInstance()
    {
        return new GlobalErrorHandler();
    }

    void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        IErrorHandler errorHandlerInstance = GetInstance();

        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
        {
            dispatcher.ErrorHandlers.Add(errorHandlerInstance);
        }
    }

    void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
        {
            if (endpoint.Contract.Name.Equals("IMetadataExchange") &&
                endpoint.Contract.Namespace.Equals("http://schemas.microsoft.com/2006/04/mex"))
                continue;

            foreach (OperationDescription description in endpoint.Contract.Operations)
            {
                if (description.Faults.Count == 0)
                {
                    throw new InvalidOperationException("FaultContractAttribute not found on this method");
                }
            }
        }
    }
}

web.config web.config

<extensions>
  <behaviorExtensions>
    <add name="errorHandler"
          type="Base.WCF.Helpers.Error_Handler.ErrorHandlerExtension, Base.WCF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>

global.asax global.asax

var builder = new ContainerBuilder();
builder.RegisterType<Base.WCF.BaseService>();
builder.RegisterType<ErrorService>().As<IErrorService>();
var IOCContainer = builder.Build();
AutofacHostFactory.Container = IOCContainer;

I cannot find any way which will allow me to inject the service in my IErrorHandler as i cannot resolve its dependencies. 我找不到任何允许我将服务注入IErrorHandler的方法,因为我无法解析其依赖关系。 The thing is that i have to register the custom IErrorHandler through the ApplyDispatchBehavior. 事情是,我必须通过ApplyDispatchBehavior注册自定义IErrorHandler。 I have also tried constructor injection in my ErrorHandlerExtension but it didn't work either. 我还在ErrorHandlerExtension中尝试了构造函数注入,但是它也不起作用。 Also all my other injections in my wcf service methods work fine. 我的wcf服务方法中的所有其他注入也都可以正常工作。

Is there any way i can inject the IErrorService in my IErrorHandler? 有什么方法可以在IErrorHandler中注入IErrorService吗?

EDIT 编辑

Based on Travis' answer I also had to resolve my other repository injections so I used the following 根据Travis的回答,我还必须解决其他存储库注入问题,因此我使用了以下内容

        using (var scope = AutofacHostFactory.Container.BeginLifetimeScope())
        {
            var svc = scope.Resolve<IErrorHistoryService>();
            scope.Resolve<IErrorHistoryRepository>();
            scope.Resolve<IUnitOfWork>();
            svc.AddError(new ErrorLog_BO());
            svc.SaveError();
        }

The short version answer here is that there's really no good way to do this. 这里简短的答案是,实际上没有很好的方法可以做到这一点。

WCF has a notoriously bad story around dependency injection. WCF在依赖注入方面臭名昭著。 The only way you can even do DI into service instances is because there's a specific IInstanceProvider interface that is used to handle creating a new instance of your service. 您甚至可以对服务实例进行DI的唯一方法是,因为存在一个特定的IInstanceProvider接口 ,该接口用于处理创建服务的新实例。

You'll notice in implementing your extension that you end up having to attach an instance of your error handler to the channel rather than having some sort of factory/function available. 您会在实现扩展时注意到,最终必须将错误处理程序的实例附加到通道,而不是具有某种可用的工厂/功能。

One not-so-great option is to use service location in your IErrorHandler . 一种不太好的选择是在IErrorHandler使用服务位置。

public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
  //log the error using the service
  var svc = AutofacHostFactory.Container.Resolve<IErrorService>();
  svc.Log(error); 
}

There are several reasons this isn't great. 造成这种情况的原因有很多。

  • It'll come out of the root container, so if anything in the IErrorService is IDisposable you'll get a memory leak because it won't get disposed until the container is disposed. 它会从根容器中出来,因此,如果IErrorService任何内容都是IDisposable ,则会发生内存泄漏,因为只有在容器被处置后才会被处置。
  • You won't be in the same lifetime scope as your services, so you won't have shared dependencies unless they're singletons. 您将不会与服务处于相同的生存期范围,因此除非它们是单例,否则您将没有共享的依赖关系。

You can sort of fix the first issue like this: 您可以排序的解决这样的第一个问题:

public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
  using(var scope = AutofacHostFactory.Container.BeginLifetimeScope())
  {
    var svc = scope.Resolve<IErrorService>();
    svc.Log(error);
  } 
}

That should at least avoid the memory leak with IDisposable instances... but you'll still have the shared dependency problem. 那至少应该避免IDisposable实例的内存泄漏...但是您仍然会遇到共享依赖项问题。 Maybe that doesn't matter. 也许没关系。 Sort of up to you. 取决于您。

But... no, most stuff in WCF doesn't run through DI so you're going to be super stuck on this and other similar things. 但是...不,WCF中的大多数内容都不能通过DI运行,因此您将被这方面以及其他类似方面所困扰。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM