使用 ELMAH 的 WCF 服务异常日志记录 [英] Exception Logging for WCF Services using ELMAH

查看:28
本文介绍了使用 ELMAH 的 WCF 服务异常日志记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用出色的 ELMAH 来处理 ASP.NET 3.5 网络中未处理的异常应用.除了使用 REST 功能使用的 WCF 服务之外,这对于所有站点都非常有效.当应用程序代码未处理的操作方法中发生异常时,WCF 会根据服务协定和配置设置以各种方式处理.这意味着异常最终不会触发 ELMAH 使用的 ASP.NET HttpApplication.Error 事件.我知道的两种解决方案是:

We are using the excellent ELMAH to deal with unhandled exceptions in an ASP.NET 3.5 web application. This works extremely well for all of the site apart from WCF services which are being consumed using the REST features. When an exception occurs within the operation methods that is not handled by the application code, WCF handles it in various ways depending on the service contracts and configuration settings. This means that the exception does not end up firing the ASP.NET HttpApplication.Error event that ELMAH uses. The two solutions I am aware of to deal with this are:

  • Wrap all method calls in a try { } catch(Exception ex) { Elmah.ErrorSignal.FromCurrentContext().Raise(ex); throw; } to explicitly call Elmah within the catch block.
  • Use IErrorHandler as described in Will Hughes' blog post Making WCF and ELMAH play nice together to factor out the call to ELMAH to a separate ErrorHandler.

第一个选项非常简单,但并不完全DRY.第二个选项只需要您在实现属性和 ErrorHandler 后使用自定义属性装饰每个服务.我是根据 Will 的 工作完成的,但我想验证这是 发布代码之前的正确方法.

The first option is extremely simple but is not exactly DRY. The second option only requires you to decorate each service with the custom attribute after implementing the attribute and the ErrorHandler. I have done this based on Will's work but I want to verify that this is the correct approach before posting the code.

有没有我错过的更好的方法?

IErrorHandler 的 MSDN 文档说HandleError 方法是进行日志记录的地方,但 ELMAH 访问HttpContext.Current.ApplicationInstance,即使 HttpContext.Current 可用,它在此方法中也为 null.在ProvideFault 方法中调用Elmah 是一种解决方法,因为设置了ApplicationInstance,但这与API 文档中描述的意图不匹配.我在这里遗漏了什么吗?文档确实指出您不应依赖在操作线程上调用的 HandleError 方法,这可能是 ApplicationInstance 在此范围内为 null 的原因.

The MSDN documenation for IErrorHandler says that the HandleError method is the place to do the logging but ELMAH accesses the HttpContext.Current.ApplicationInstance, which is null within this method even though HttpContext.Current is available. Making the call to Elmah within the ProvideFault method is a workaround as ApplicationInstance is set but this does not match the intent described in the API documentation. Am I missing something here? The documentation does state that you should not rely on the HandleError method being called on the operation thread which may be why ApplicationInstance is null in this scope.

推荐答案

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

The solution from my blog post (referenced in the OP) was based on an existing solution we were/are using to alter HTTP Response Codes during an error state.

因此,对我们来说,将异常传递给 ELMAH 只是一行更改.如果有更好的解决方案,我也很想知道.

So, for us it was a one-line change to pass the Exception to ELMAH. If there's a better solution, I'd love to know about it too.

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

For Posterity/Reference, and potential improvement - here's the code from the current solution.

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 服务:

Usage Example

Decorate your WCF Services with the ServiceErrorBehaviour Attribute:

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

这篇关于使用 ELMAH 的 WCF 服务异常日志记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆