我正在尝试在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();
}
答案 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运行的,因此您将对这些以及其他类似的东西一无所知。