2010-12-16 187 views
8

我有很多遺留代碼,現在是WCF REST服務的後端 - 它以前是通常的WCF服務後端,如果這很重要的話。我想實現一種機制,可以捕捉任何方法中的任何異常並分析它。如果它是一個已知的錯誤,它將被處理並變成一個友善的外觀錯誤。WCF REST服務 - 通用異常處理

我知道我可以拋出FaultExceptionWebProtocolException而不是'平常'異常,但是有很多地方在代碼中拋出異常,並且尋找所有這些異常是一個非常痛苦的選擇。

我想補充一點,創建一個新的行爲凌駕於標準WebHttpBehavior.AddServerErrorHandlers方法,並增加了我的錯誤處理程序(IErrorHandler實現)到終點調度錯誤處理程序集合中的端點行爲擴展。在錯誤處理程序內部,我分析異常並基於此異常創建(或不創建)期望的故障。

我希望這種機制能夠爲任何已知的異常返回自定義數據,但我錯了。好的微軟已經實現了一個美妙的不可避免的WebHttpBehavior2,它無條件地將內部Microsoft.ServiceModel.Web.WebErrorHandler添加到端點調度程序錯誤處理程序集合的末尾。這個處理程序會忽略所有以前執行的處理程序,只識別一小組例外,而大多數被解釋爲「內部服務器錯誤」,僅此而已。

問題是我是否在正確的路徑上,並且有一種方法可以在WCF REST機制中禁用此處理程序,或者將其引入一個新的異常(例如,當任何異常被捕獲,它首先由我處理處理程序,如果它們拋出/返回,例如FaultException,那麼這個新異常將提供給Microsoft.ServiceModel.Web.WebErrorHandler而不是原來的異常)。如果我所有使用IErrorHandler和行爲擴展的實驗都毫無價值,那麼有什麼選擇?再次,我真的不想修改異常拋出邏輯,我想要一個地方來捕捉異常並處理它們。

非常感謝!

回答

7

當您將WCF SOAP服務更改爲REST時,錯誤報告和處理更改的整個思路。

在SOAP中,錯誤是您合同的一部分。在REST中,它們只是成爲您在HTTP響應代碼和說明中輸出的代碼。

這裏是一個catch片段:

catch (Exception e) 
{ 
    Trace.WriteLine(e.ToString()); 

    OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse; 
    response.StatusCode = System.Net.HttpStatusCode.UnsupportedMediaType; // or anything you want 
    response.StatusDescription = e.Message; 
    return null; // I was returning a class 
} 

所以我建議您創建爲您創建相應的錯誤代碼,放在了響應的輔助代碼。

+0

這種捕獲應該被添加到每種服務方法,對吧?或者有沒有辦法將它寫在某個地方只處理一次以處理所有異常?我喜歡基於行爲的方法,因爲它爲所有異常定義了一個通用處理程序,並且我不必擔心爲每個單一方法處理和處理異常。最好的情況是我爲端點中的所有服務定義了一個處理器。我無法用你的方法達到這個目標,我可以嗎? – 2010-12-17 08:30:07

+0

設置'StatusDescription'不起作用!響應始終具有通用狀態描述。無論如何解決它? – Hemant 2011-01-13 07:19:30

+0

它有。您可以使用fiddler檢查服務器發出的消息中的....,但是您可能會發現,各種瀏覽器或不同的實現可能會忽略該描述,只是使用代碼映射到預定義的消息。我遇到了一個我正在編寫的Android應用程序的問題,並最終設置了描述以及更改方法簽名,以便我可以返回一個字符串。哎呀! **這就是爲什麼我永遠不會使用WCF REST了。** – Aliostad 2011-01-13 09:19:02

2

這是我在過去

public class MyServerBehavior : IServiceBehavior { 

     public void AddBindingParameters(ServiceDescription serviceDescription, 
      ServiceHostBase serviceHostBase, 
      Collection<ServiceEndpoint> endpoints, 
      BindingParameterCollection bindingParameters) { 

     } 

     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
              ServiceHostBase serviceHostBase) { 

      foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers) { 
       chDisp.IncludeExceptionDetailInFaults = true; 
       if (chDisp.ErrorHandlers.Count > 0) { 
        // Remove the System.ServiceModel.Web errorHandler 
        chDisp.ErrorHandlers.Remove(chDisp.ErrorHandlers[0]); 
       } 
       // Add new custom error handler 
       chDisp.ErrorHandlers.Add(new MyErrorHandler()); 

      } 

     } 

     public void Validate(ServiceDescription serviceDescription, 
          ServiceHostBase serviceHostBase) { 
     } 

    } 

MyErrorHandler是我的類實現IErrorHandler。

+0

這看起來與我所做的非常相似。它是否適用於REST服務,還是僅適用於SOAP?如果它適用於REST服務,那麼您是如何配置服務的?如果僅僅用於SOAP,那麼謝謝,但就我現在看到的而言,REST是完全不同的故事。 – 2010-12-17 08:32:54

+1

@Michael我爲它做了REST服務。我是自我託管的,實際上創建了我自己的派生服務主機來設置行爲。它都是基於代碼的,沒有XML。 – 2010-12-17 12:10:41

+0

自我託管,我明白了...這就是我想的但被認爲太複雜。謝謝! – 2010-12-17 15:28:29