стратегии для обработки ошибок в ac # async лямбда-мире? - PullRequest
1 голос
/ 13 сентября 2011

Раньше я писал толстый клиентский код на c #, который генерировал бы исключения в машинном отделении (скажем, из-за сбоя в сети) и ожидал, что кто-то выше меня справится с этим.В конечном счете, всплывающее окно с попыткой / захватом всего приложения, которое будет обрабатывать остатки («Неожиданное исключение в панели foo, нажмите для подробностей, обратитесь в службу поддержки ....»), а также, возможно, обработчик исключений для всего домена приложения на всякий случай.

Сейчас я пишу «толстый» клиент в Silverlight и больше не знаю, что делать.Большие объемы кода машинного отделения выполняются как обратные вызовы, управляемые сетевыми событиями, и затем я вызываю лямбду, предоставленную мне исходным вызывающим абонентом;но они давно ушли.Я не могу выдать исключение в них, нет стека, чтобы пузыриться.Я не могу заставить их расслабиться.Они все еще находятся в состоянии ожидания (что бы это ни значило для этого конкретного асинхронного вызова).

Я вижу AsyncEventCompletedArgs с его трюком RaiseExceptionIfNeeded.Использование этого, кажется, подвергает мою сантехнику низкого уровня коду более высокого уровня (например, MVVM, MVC, ...).Я хочу помочь коду верхнего уровня «делать правильные вещи» по умолчанию, как они это делали в старые добрые времена, основанные на синхронизации / исключениях.Но это не помогает.Они читают результат из экземпляра AsyncArgs, который выбрасывает и обратный вызов умирает, оставляя их все равно логически висящими

В любом случае - надеюсь, это имеет смысл.Есть ли у кого-нибудь проекты, опыт, которым они хотят поделиться.Что делают какие-либо из SL MVVM, MVC-фреймворки?

Примечание. Я не говорю о новых модных Async-компонентах в c # 5 (это поможет?)

(Вероятно,будет закрыт как недостаточно конкретный, слишком субъективный и т. д., вздох)

Ответы [ 4 ]

2 голосов
/ 13 сентября 2011

Вы можете попросить вызывающую сторону предоставить лямбду для успешного завершения, а также лямбда, которая принимает исключение для случаев, когда в вашем коде обнаруживается исключение.

Reactive Extensions позволяет это при подписке нанаблюдаемое.

Что-то вроде:

asyncCall.Subscribe(result => DoSomething(result), ex => Oops(ex));
1 голос
/ 13 сентября 2011

Если ваше требование включает в себя значимые параллельные незавершенные асинхронные операции, не беспокойтесь о прочтении этого ответа.Однако, если операции вызываются последовательно (одна не вызывается до тех пор, пока другая не завершится), как это может показаться, вы можете найти материал, на который здесь ссылаются, несколько полезный.

Обработка асинхронного кода в Silverlight подвластнакоторый я проявляю большой интерес.Я написал несколько блогов о том, что я называю AsynchOperationService, который позволяет писать код с использованием простого синхронного стиля и поддерживает хорошую обработку ошибок.

Выберите их из этого списка .

Rx может быть вариантом, это выглядит так, как будто оно будет мощным.Однако это сложно, изначально он был разработан для обработки потока входящих событий.Я не убежден (хотя я признаю, что мое исследование все еще мелкое), что оно хорошо подходит для операции «Начни что-нибудь, ответь позже на это что-то заканчивая».

Лично мне нравятся вещи, которые будут простыми и прямымивперед, но очевидно, что мне нужно полностью изменить способ, которым я кодирую, чтобы должным образом включить мощь Rx, и я совершенно уверен, что полученный код не будет таким легким для чтения.

Принимая во внимание AsyncOperationService имеет очень легкий отпечаток, и как только я создал несколько полезных однострочных функций, результирующая последовательность кода довольно проста для чтения.

Так в чем же подвох?Ну, есть один и он либо именно то, что вам нужно, либо работает именно против того, что вам нужно.Подход работает в предположении, что серию асинхронных операций необходимо выполнять последовательно.Если ваше требование касается значительных параллельных операций, то в его нынешнем виде AsyncOperationService не для вас (хотя это может измениться).

0 голосов
/ 13 сентября 2011

Хитрость заключается в том, чтобы вернуть Исключение в поток пользовательского интерфейса. Вы все еще хотите бросить, пока кто-то не обработает это как прежде, но вы должны захватить это на верхнем уровне потока и передать его обратно в основной поток и обработать это там как обычно. Есть несколько способов сделать это, самый простой в Silverlight - это использовать BackgroundWorker, но простой способ сделать это - обеспечить обратный вызов всем асинхронным методам, которые возвращают значения или ошибки. Примерно так:

DoAsync(
  () => BackgroundThreadWork(), // executed on background thread
  result => {                   // executed on UI thread
    if(result.Error != null)
      throw result.Error;
    HandleResultOnUIThread(result.Value);
  });

Вот пример очень простой очереди асинхронных действий, которая может быть довольно легко преобразована в дружественную для Silverlight версию:

Простой ActionQueue в MetaSharp

Я использую очередь, потому что она позволяет мне гарантировать порядок работы, выполняемой в фоновых потоках. Когда у вас есть куча асинхронных операций, очень легко попасть в условия гонки и так далее, очередь - это отличная структура, гарантирующая порядок их выполнения, даже если все они фактически асинхронные. Группа queueGroup предназначена для действий, которые вы также хотите выполнять параллельно и асинхронно.

0 голосов
/ 13 сентября 2011

Я использую код следующей структуры для обработки асинхронных проблем:

        void ClientAsyncOperationCompleted(object sender, AsyncOperationEventArgs e)
        {
            if (e.Error == null) {
                //Normal execution path
            }
            else {
                //you can put your structured exception handling code here around e.Error
                if(e.Error is ConcreteException) {
                   //concrete exception handling
                }
                else {
                   //general exception handling
                } 
            }
        }

Если метод выполняется асинхронно, нет способа получить синхронный выброс исключения, за исключением случаев, когда мы оборачиваем асинхронный метод и синхронизируем его выполнение, используя некоторую конструкцию синхронизации потоков, например, ManualResetEvent. Поэтому, если мы примем, что мы обрабатываем исключение асинхронно, внутри AsyncCompleted вы можете вызвать нужный метод Oops (Exception e) следующим образом:

void ClientAsyncOperationCompleted(object sender, AsyncOperationEventArgs e)
{
    if (e.Error == null) {
       //Normal execution path
    }
    else {
       Oops(e.Error);
    }
}

это без Rx, что довольно сложно, но мощно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...