Caliburn.Micro: восстановление после исключения в IResult - PullRequest
2 голосов
/ 03 февраля 2011

Это было опубликовано на Caliburn.Micro обсуждения также.Я действительно ищу советы и мнения по поводу лучшего способа решения.

Допустим, у меня есть следующее действие

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

StationSave - это обертка IResult для простого (WCF) вызова службы,Служба использует FaultContract / FaultException для сбоев.

В случае сбоя пользователь должен быть уведомлен, и FaultContract будет содержать некоторую полезную информацию о том, что пошло не так.В настоящее время результат Save перехватывает исключение и вставляет его в ResultCompletionEventArgs события Completed.Таким образом, SequentialResult, созданный конвейером, отменяется (из-за ошибки), в результате чего экран остается в занятом состоянии.

Что мне действительно нужно, так это идеи о наилучшем способе восстановления послеОшибка (удалить состояние занятости) и уведомить пользователя (у меня есть несколько реализаций IResult для различных стилей уведомления, которые я хотел бы использовать) о деталях, представленных в договоре об ошибках.Присоединяясь к событию Completed в моей виртуальной машине, я могу получить сообщение об ошибке, но на данный момент я больше не в контексте конвейера действий, поэтому любые IResults, которые я хотел бы использовать (MakeNotBusy и моя реализация уведомления уведомления), я долженвыполнить вручную (и я должен был бы создать свой собственный ActionExecutionContext, что я не хочу делать).

Я взглянул на спасательный фильтр Марко Амендолы для Caliburn.Micro с здесь, но, опять же, я не могу передать результаты из метода Rescue.

Я что-то упустил из виду?Как другие справляются с этой ситуацией?

1 Ответ

1 голос
/ 09 февраля 2011

Оба Роб Айзенберг и Марко Амендола предоставили возможные решения на форуме CodePlex .

Я выбрал Марко 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>();
}
...