2011-02-02 80 views
2

這也發佈在Caliburn.Micro discussions處。我真的在尋求最佳解決方法的建議和意見。Caliburn.Micro:從IResult中的異常中恢復

說我有以下操作

public IEnumerable<IResult> SaveStation() 
{ 
    yield return Busy.MakeBusy(); 
    yield return new StationSave(_station); 
    yield return Busy.MakeNotBusy(); 
    yield return Show.Tab<StationBrowseViewModel>(); 
} 

StationSave是圍繞一個簡單的(WCF)服務調用的IResult包裝。該服務使用FaultContract/FaultException進行失敗。

在發生故障時,需要通知用戶並且FaultContract將包含有關出錯的一些有用信息。目前,Save結果捕獲異常並將其插入到Completed事件的ResultCompletionEventArgs中。通過這樣做,由管道創建的SequentialResult被取消(由於錯誤),從而使屏幕處於繁忙狀態。

我真正追求的是從錯誤中恢復的最佳方式(除去忙碌狀態),並通知用戶(我有幾個IResult實現用於不同樣式的通知,我希望使用)的故障合同中提供的詳細信息。通過附加到我的虛擬機中的Completed事件,我可以得到錯誤,但此時我不再處於Action管道的上下文中,因此我想要使用的任何IResults(MakeNotBusy和我的節目通知實現)手動執行(我不得不新建自己的ActionExecutionContext,我不想這麼做)。

我已經看過Marco Amendola的Caliburn.Micro救援過濾器here,但我再也不能從Rescue方法中傳回IResults。

我錯過了一些明顯的東西嗎?其他人如何處理這種情況?

回答

1

Rob EisenbergMarco Amendola均在CodePlex forum中提供了可能的解決方案。

我選擇了從他的filters implementation中選擇Marco的RescueAttribute並稍加修改以允許從救援方法中執行更多IResult。這是需要改變RescueAttribute.HandleException

protected override bool HandleException(ActionExecutionContext context, 
             Exception ex) 
{ 
    var method = context.Target 
         .GetType() 
         .GetMethod(MethodName, new[] { typeof(Exception) }); 
    if (method == null) return false; 

    try 
    { 
     var result = method.Invoke(context.Target, new object[] { ex }); 

     if (result is bool) 
      return (bool) result; 

     if (result is IResult) 
      result = new[] { result as IResult }; 
     if (result is IEnumerable<IResult>) 
      Coroutine.Execute(((IEnumerable<IResult>) result).GetEnumerator(), context); 
     else if (result is IEnumerator<IResult>) 
      Coroutine.Execute(((IEnumerator<IResult>) result), context); 

     return true; 
    } 
    catch 
    { 
     return false; 
    } 
} 

這樣可以讓我的虛擬機執行以下操作:

public IEnumerable<IResult> Rescue(Exception ex) 
{ 
    yield return Busy.MakeNotBusy(); 
    // in practice pass exception details through to notification 
    yield return new NotificationPopup("Save station failed"); 
} 

[Rescue] 
public IEnumerable<IResult> SaveStation() 
{ 
    yield return Busy.MakeBusy(); 
    yield return new StationSave(_station); 
    yield return Busy.MakeNotBusy(); 
    yield return Show.Tab<StationBrowseViewModel>(); 
}