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

时间:2018-10-23 18:23:53

标签: c# rest wcf autofac

我正在尝试在wcf项目中实现一个简单的通用错误处理程序,但要注意的是我想注入一个服务(使用autofac)以保存所有异常。我到处都看过,什么也没找到。我正在将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

<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

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

我无法找到任何方法允许我将服务注入到IErrorHandler中,因为我无法解析其依赖关系。事情是,我必须通过ApplyDispatchBehavior注册自定义IErrorHandler。我还在ErrorHandlerExtension中尝试了构造函数注入,但是它也不起作用。我的wcf服务方法中的所有其他注入也都可以正常工作。

有什么方法可以在IErrorHandler中注入IErrorService吗?

编辑

基于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();
        }

1 个答案:

答案 0 :(得分:1)

这里的简短答案是,实际上没有很好的方法来完成此操作。

WCF在依赖注入方面臭名昭著。甚至可以对服务实例进行DI的唯一方法是,因为有一个特定的IInstanceProvider interface用于处理创建服务的新实例。

在实施扩展程序时,您会发现最终必须将错误处理程序的实例附加到通道上,而不是具有某种可用的工厂/功能。

一个不太好的选择是使用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); 
}

不好的原因有很多。

  • 它将从根容器中出来,因此如果IErrorService中的任何内容是IDisposable,您将遇到内存泄漏,因为只有在容器被处置后它才会被处置。 / li>
  • 您将不会与服务处于相同的生存期范围,因此除非它们是单例,否则您将没有共享的依赖关系。

您可以之类的修复第一个问题,如下所示:

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);
  } 
}

那至少应该避免IDisposable实例的内存泄漏...但是您仍然会遇到共享依赖项问题。也许没关系。取决于您。

但是...不,WCF中的大多数内容都不是通过DI运行的,因此您将对这些以及其他类似的东西一无所知。