使用ELMAHloggingWCF服务exception

我们正在使用优秀的ELMAH来处理ASP.NET 3.5 Web应用程序中未处理的exception。 除了使用RESTfunction消耗的WCF服务之外,这对于所有网站都非常有效。 当在应用程序代码不处理的操作方法中发生exception时,WCF将根据服务合同和configuration设置以各种方式处理它。 这意味着这个exception不会引发ELMAH使用的ASP.NET HttpApplication.Error事件。 我知道处理这两个解决scheme是:

  • 将所有的方法调用封装在一个try {} catch(Exception ex){Elmah.ErrorSignal.FromCurrentContext()。Raise(ex); 扔; }在catch块中显式调用Elmah。
  • 使用IErrorHandler将在Will Hughes的博客文章中描述使WCF和ELMAH一起玩起来将ELMAH调用分解为一个单独的ErrorHandler。

第一个选项非常简单,但不完全干燥 。 第二个选项只需要在实现属性和ErrorHandler后用装饰属性装饰每个服务。 我已经完成了基于威尔的工作,但我想validation这是发布代码之前正确的方法

有没有更好的办法,我错过了?

IErrorHandler的MSDN文档说, HandleError方法是做logging的地方,但是ELMAH访问HttpContext.Current。 ApplicationInstance ,即使HttpContext.Current可用,此方法内为null。 在ProvideFault方法中调用Elmah是一种解决方法,因为ApplicationInstance已设置,但与API文档中描述的意图不符。 我在这里错过了什么? 该文档确实说明,您不应该依赖在操作线程上调用的HandleError方法,这可能是为什么ApplicationInstance在此范围内为null。

我的博文中的解决scheme(在OP中引用)是基于我们用来在错误状态期间更改HTTP响应代码的现有解决scheme。

所以,对于我们来说,将例外传递给ELMAH是一个单行的改变。 如果有更好的解决scheme,我也很想知道。

对于后继/参考和潜在的改进 – 这里是当前解决scheme的代码。

HttpErrorHandler和ServiceErrorBehaviourAttribute类

using System; using System.ServiceModel; using System.ServiceModel.Dispatcher; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.Collections.ObjectModel; using System.Net; using System.Web; using Elmah; namespace YourApplication { /// <summary> /// Your handler to actually tell ELMAH about the problem. /// </summary> public class HttpErrorHandler : IErrorHandler { public bool HandleError(Exception error) { return false; } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { if (error != null ) // Notify ELMAH of the exception. { if (System.Web.HttpContext.Current == null) return; Elmah.ErrorSignal.FromCurrentContext().Raise(error); } } } /// <summary> /// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))] /// ...and errors reported to ELMAH /// </summary> public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior { Type errorHandlerType; public ServiceErrorBehaviourAttribute(Type errorHandlerType) { this.errorHandlerType = errorHandlerType; } public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { } public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) { } public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) { IErrorHandler errorHandler; errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType); foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers) { ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher; channelDispatcher.ErrorHandlers.Add(errorHandler); } } } } 

用法示例

使用ServiceErrorBehaviour属性装饰您的WCF服务:

 [ServiceContract(Namespace = "http://example.com/api/v1.0/")] [ServiceErrorBehaviour(typeof(HttpErrorHandler))] public class MyServiceService { // ... } 

创buildBehaviorExtensionElement时,甚至可以使用config激活行为:

 public class ErrorBehaviorExtensionElement : BehaviorExtensionElement { public override Type BehaviorType { get { return typeof(ServiceErrorBehaviourAttribute); } } protected override object CreateBehavior() { return new ServiceErrorBehaviourAttribute(typeof(HttpErrorHandler)); } } 

configuration:

 <system.serviceModel> <extensions> <behaviorExtensions> <add name="elmah" type="Namespace.ErrorBehaviorExtensionElement, YourAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> </behaviorExtensions> </extensions> <behaviors> <serviceBehaviors> <behavior> <elmah /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> 

这样也可以将ELMAH与RIA服务结合使用!

我已经完成了基于威尔的工作,但我想validation这是发布代码之前正确的方法。

我认为这是一个很好的方法(对这个postWill的赞誉!)。 我不认为威尔或你在这里错过了什么。 实现IErrorHandler是捕获所有可能的服务器端exception的首选方法,否则可能会导致通信通道出现故障(被拆除),因此这是一个很自然的地方,可以像ELMAH一样logging日志。

渣子

这对某些人来说可能是显而易见的,但是我花了很长一段时间,试图找出为什么我的HttpContext.Current是空的,尽pipeWill Hughes的所有答案都是如此。 不好意思,我意识到这是因为我的WCF服务是由MSMQ消息激活的。

我最终重写了ProvideFault()方法:

 if (HttpContext.Current == null) { ErrorLog.GetDefault(null).Log(new Error(error)); } else { ErrorSignal.FromCurrentContext().Raise(error); } 

我无法得到build议的答案与WCF数据服务工作。 我连线的行为属性等,但仍没有得到任何logging的错误。 相反,我最终将以下内容添加到服务实现中:

 protected override void HandleException(HandleExceptionArgs args) { Elmah.ErrorSignal.FromCurrentContext().Raise(args.Exception); base.HandleException(args); } 

我还没有尝试过使用REST的东西来明确地做这件事,而且还没有自己使用ELMAH,但另一个值得研究的方法可能是使用IDispatchMessageInspector而不是IErrorHandler来挂钩WCF。