2012-10-02 73 views
1

當實現IErrorHandler接口並將其添加到WCF服務中的調度程序時應用程序我遇到了一些奇怪的行爲。 只有HandleError方法被觸發,而不是ProvideFault方法。在WCF服務應用程序或WCF服務庫中實現IErrorHandler

當在WCF服務中使用相同的代碼和配置時這兩種方法都會觸發代碼中的異常。

實施例:

public class ErrorHandler : IErrorHandler, IServiceBehavior 
{ 
    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault) 
    { 
     // Provide the fault 
    } 

    public bool HandleError(Exception error) 
    { 
     // If handled return true, otherwise false 
    } 

    // Validate 
    // AddBindingParameters 
    // ApplyDispatchBehavior 
} 

public class ErrorHandlerBehavior : BehaviorExtensionElement 
{ 
    public override Type BehaviorType 
    { 
     get { return typeof(ErrorHandler); } 
    } 

    protected override object CreateBehavior() 
    { 
     return new ErrorHandler(); 
    } 
} 

而且在Web.config:

<extensions> 
     <behaviorExtensions> 
     <add name="ErrorLogging" type="Service.ErrorHandlerBehavior, Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
     </behaviorExtensions> 
    </extensions> 
... 
     <serviceBehaviors> 
     <behavior> 
      <ErrorLogging /> 
     </behavior> 
     </serviceBehaviors> 

的代碼和配置是相同的(雖然配置在Web.config中在服務應用程序,我應用。服務庫中的.config)。

通過插入斷點在ProvideFaultHandleError我可以看到ProvideFault只是援引了服務圖書館 - 怎麼能這樣呢?我錯過了什麼嗎?

編輯

看來,當服務操作的調用簽名ProvideFault不調用具有其他然後返回類型的基本類型,如:

public IEnumerable<MyType> GetMyType(string s1) 
{ 
    throw new Exception("Testing..."); 
} 

...將不會觸發ProvideFault

但是:

public bool DoStuff(string s1, string s2) 
{ 
    throw new Exception("Testing..."); 
} 

...沒有觸發ProvideFault

回答

0

尼克拉斯傑森,你接近正確的答案。 我剛剛遇到了與IEnumerable相同的問題,但設法解決它,而不是改變返回類型。

在我的情況下,問題的原因是該方法使用yield return語句。正如您可能知道的那樣,返回IEnumerable並使用yield return返回元素的方法被編譯爲「狀態機」。事實上,它返回IEnumerable實例,該實例返回迭代器,哪些方法實現該狀態機。這個強大的功能位於LINQ的核心,它允許延遲執行 - 狀態機只在需要另一個元素時才起作用。

在WCF的情況下,我想我知道會發生什麼。 WCF的行爲有點像這樣:

  1. 它調用該方法。

  2. 如果該方法失敗,WCF會將異常傳遞給ErrorHandler方法(它們都是)。

  3. 如果方法成功,WCF將準備響應。它按照響應格式序列化方法返回的對象。

  4. 如果系列化失敗(還有什麼比方法失效預期的那樣),WCF傳遞例外您的ErrorHandler,但僅限於方法的HandleError。出於某種原因,ProvideFault在此階段未被調用。

  5. 如果串行化成功,序列化的對象被髮送到客戶端。

現在考慮這兩個例子:

public bool DoStuff(); 
public IEnumerable<bool> DoALotOfStuff(); 

DoStuff肯定無法在步驟2中,但DoALotOfStuff不!請記住,它是一個狀態機,執行延遲到您查詢第一個元素的那一刻。所以,該方法不會失敗,它只返回IEnumerable實例,一旦你需要這些元素,它就準備給你枚舉器。因此,WCF對該方法返回的內容感到滿意,因此繼續進行序列化。這就是它讓你陰險的例外!現在

,解決方法很簡單 - 只是不推遲執行。返回一個「真正的」可枚舉實例,如List,而不是「狀態機」。

public IEnumerable<bool> DoALotOfStuff() 
{ 
    return _DoALotOfStuff().ToList(); 
} 

protected IEnumerable<bool> _DoALotOfStuff() 
{ 
    yield return true; 
    yield return false; 
    throw new Exception("Testing..."); 
} 

現在,如果該方法失敗,它將失敗,因此您需要調用ProvideFault。