如何使用ELMAH记录WCF服务的例外情况?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (16)

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

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

第一个选项非常简单,但不完全dry。第二个选项只需要在实现属性和ErrorHandler后使用自定义属性修饰每个服务。我已经完成了基于Will的工作,但我想在发布代码之前验证这是正确的方法

有没有更好的方式,我错过了?

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

提问于
用户回答回答于

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

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

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

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
{
  // ...
}
用户回答回答于

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

public class ErrorBehaviorExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(ServiceErrorBehaviourAttribute); }
    }

    protected override object CreateBehavior()
    {
        return new ServiceErrorBehaviourAttribute(typeof(HttpErrorHandler));
    }
}

配置:

<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服务结合使用!

扫码关注云+社区