使用 ELMAH 的 WCF 服務的異常日誌記錄
我們正在使用出色的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 { // ... }