Caliburn.Micro:从IResult中的异常中恢复

时间:2011-02-02 22:57:15

标签: c# silverlight silverlight-4.0 caliburn.micro

这也发布在Caliburn.Micro discussions。我真的在寻找有关最佳解决方法的建议和意见。

说我有以下行动

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实现,用于不同的通知方式,我想使用)故障合同中提供的详细信息。通过附加到我的VM中的Completed事件,我可以得到错误,但此时我不再处于Action管道的上下文中,因此我想使用任何IResults(MakeNotBusy和我的show notification实现)我必须手动执行(我必须新建自己的ActionExecutionContext,我不想这样做。)

我从here看了一下Marco Amendola对Caliburn.Micro的救援过滤器,但我再也无法从Rescue方法中传回IResults。

我错过了一些明显的东西吗?其他人如何处理这种情况?

1 个答案:

答案 0 :(得分: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;
    }
}

这允许我的VM中的以下内容:

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>();
}