Asp.net

使用 ELMAH 的 WCF 服務的異常日誌記錄

  • May 22, 2009

我們正在使用出色的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 的部落格文章使 WCF 和 ELMAH 很好地協同工作中所述的IErrorHandler將對 ELMAH 的呼叫分解為單獨的 ErrorHandler。

第一個選項非常簡單,但並不完全是DRY。第二個選項只需要你在實現屬性和ErrorHandler之後用自定義屬性來裝飾每個服務。我是根據Will 的工作完成的,但我想在發布程式碼之前驗證這是正確的方法。

我錯過了更好的方法嗎?

IErrorHandler的 MSDN 文件說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
{
 // ...
}

引用自:https://stackoverflow.com/questions/895901