Лучший способ перехватить исключение WCF в Silverlight?

StackOverflow https://stackoverflow.com/questions/94610

  •  01-07-2019
  •  | 
  •  

Вопрос

У меня есть приложение Silverlight 2, которое использует службу WCF.Таким образом, он использует асинхронные обратные вызовы для всех вызовов методов сервиса.Если служба не запущена, или она выходит из строя, или сеть выходит из строя и т.д. До или во время одного из этих вызовов, как и следовало ожидать, генерируется исключение.Проблема в том, что я не знаю, как перехватить это исключение.

  • Поскольку это асинхронный вызов, я не могу обернуть свой вызов begin блоком try / catch и заставить его получить исключение, которое происходит после того, как программа перешла с этой точки.

  • Поскольку прокси-сервер службы генерируется автоматически, я не могу установить блок try / catch для каждой сгенерированной функции, которая вызывает EndInvoke (где на самом деле появляется исключение).Эти сгенерированные функции также окружены внешним кодом в стеке вызовов, так что больше в стеке некуда поместить try / catch .

  • Я не могу поместить try / catch в свои функции обратного вызова, потому что исключение возникает до того, как они будут вызваны.

  • В моем App.xaml.cs есть функция Application_UnhandledException, которая фиксирует все необработанные исключения.Я мог бы использовать это, но это кажется грязным способом сделать это.Я бы предпочел зарезервировать эту функцию для действительно неожиданных ошибок (иначе багов) и не создавать код в этой функции для каждого обстоятельства, с которым я хотел бы разобраться определенным образом.

Я упускаю очевидное решение?Или я застрял, используя Application_UnhandledException?

[Править]
Как упоминалось ниже, свойство Error - это именно то, что я искал.Что приводит меня в замешательство, так это тот факт, что исключение генерируется и, похоже, не перехвачено, но выполнение может продолжаться.Это запускает событие Application_UnhandledException и заставляет VS2008 прерывать выполнение, но продолжение работы в отладчике позволяет продолжить выполнение.На самом деле это не проблема, это просто кажется странным.

Это было полезно?

Решение

Я проверяю свойство Error аргументов события в обработчике завершенных событий метода service.У меня не было проблем с тем, что обработчик событий не вызывался.В случае, когда сервер выходит из строя, вызов занимает несколько секунд, затем возвращается с исключением ProtocolException в свойстве Error.

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

Другие советы

Я нашел тема на форуме там говорилось об этом, и в нем упоминается, что наилучшей практикой является использование свойства Error .Основываясь на этой теме и моем собственном опыте, вот к какому выводу я могу прийти:

  • В обычном .СЕТЕВОМ коде сгенерированный прокси-класс обрабатывает исключение должным образом, помещая исключение в свойство Error вместо того, чтобы выдавать его.

  • В Silverlight сгенерированный прокси-класс устанавливает свойство Error, но не обрабатывает исключение полностью.Исключение улавливается отладчиком, который выводит окно исключения с сообщением "ProtocolException не был обработан пользовательским кодом".Несмотря на это сообщение, исключение, похоже, на самом деле не попадает в функцию Application_UnhandledException.

Я бы ожидал, что это одна из вещей, которые они исправят в финальной версии.

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

Ты можешь забыть о Исключение Application_UnhandledException при обратных вызовах asyn-клиента причина, по которой:

Application_UnhandledException только исключения, запущенные в потоке пользовательского интерфейса, могут быть перехвачены приложением.Необработанные исключения

Это означает...вообще не вызывается для асинхронного вызова WCF :-).

Проверьте подробный ответ от MSFT

http://silverlight.net/forums/t/21828.aspx

Здравствуйте, приложение может перехватывать только исключения, запущенные в потоке пользовательского интерфейса.Необработанные исключения.Он не может перехватывать исключения из других потоков.Вы можете попробовать это, чтобы устранить проблему:В Visual Studio в меню Debug выберите пункт Exceptions (Исключения).Затем проверьте "Исключения среды выполнения Common Language".Это заставит отладчик останавливаться всякий раз, когда генерируется исключение.Но обратите внимание, что иногда это может быть довольно раздражающим, даже если исключение уже перехвачено.Вы можете использовать флажки для фильтрации исключений, которые вы хотите перехватить.

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

Спасибо

Braulio

УПС....

Извините за неправильный ответ с моей стороны (ну, парень из MSFT не нажал кнопку написать ответ, обратные вызовы службы вызываются в том же потоке пользовательского интерфейса), дело в том, что

Подробная информация:

- In development even detaching from the debugger, this method is never reached. 
- On the production environment yes.

Я предполагаю, что-то связанное с параметрами Visual Studio и перехватом исключений.

Более подробная информация в этой теме http://silverlight.net/forums/p/48613/186745.aspx#186745

Довольно интересная тема.

С Silverlight 3 отладчик Visual Studio улавливает эти исключения, так что обработчик исключений - что приводит к путанице - никогда не достигается.Однако при запуске без отладчик, обработчик исключений вызывается, как и ожидалось.Я думаю, это нормально, пока человек осознает это.Я признаю, что потратил несколько часов впустую, пытаясь понять, как разобраться во внутренней работе Silverlight / Wcf / Browser, чтобы добраться до моего исключения.Не ходи туда.

Я не сантехник, поэтому я решил создать свой собственный класс обслуживания WCF, который переопределяет некоторые функциональные возможности файла класса "reference.cs", который автоматически генерируется Visual Studio, затем я добавил свои собственные блоки try / catch для обнаружения ошибок связи.

Класс, который я создал, выглядит примерно так:

public class myWCFService : MyWCFServiceClient
{

    protected override MyController.MyService.IMyWCFService CreateChannel()
    {
        return new MyWCFServiceClientChannel(this);
    }

}

private class MyWCFServiceClientChannel : ChannelBase<MyController.MyService.IMyWCFService>, MyController.MyService.IMyWCFService
{
    /// <summary>
    /// Channel Constructor
    /// </summary>
    /// <param name="client"></param>
    public MyWCFServiceClientChannel(System.ServiceModel.ClientBase<MyController.MyService.IMyWCFService> client) :
    base(client)
    {
    }
    /// <summary>
    /// Begin Call To RegisterUser
    /// </summary>
    /// <param name="memberInformation"></param>
    /// <param name="callback"></param>
    /// <param name="asyncState"></param>
    /// <returns></returns>
    public System.IAsyncResult BeginRegisterUser(MyDataEntities.MembershipInformation memberInformation, System.AsyncCallback callback, object asyncState)
    {               
        object[] _args = new object[1];
        _args[0] = memberInformation;
        System.IAsyncResult _result = base.BeginInvoke("RegisterUser", _args, callback, asyncState);
        return _result;               
    }
    /// <summary>
    /// Result from RegisterUser
    /// </summary>
    /// <param name="result"></param>
    /// <returns></returns>
    public MyDataEntities.MembershipInformation EndRegisterUser(System.IAsyncResult result)
    {
        try
        {
            object[] _args = new object[0];
            MyDataEntities.MembershipInformation _result = ((MyDataEntities.MembershipInformation)(base.EndInvoke("RegisterUser", _args, result)));
            return _result;
        }
         catch (Exception ex)
        {
            MyDataEntities.MembershipInformation _result = new MyDataEntities.MembershipInformation();
            _result.ValidationInformation.HasErrors = true;
            _result.ValidationInformation.Message = ex.Message;
            return _result;
        }
    }
}

Использование пользовательского генератора прокси-серверов WCF является хорошим решением для обработки асинхронных исключений в Silver-light.Click здесь чтобы загрузить исходный код.

С XNA на WP7 я обнаружил, что у меня не было выбора, кроме как вручную добавлять try / catch к различным методам async End * functionName *();ничто другое, что я пробовал, не предотвратило бы сбой приложения и завершение работы, когда сервер был недоступен.Это настоящая пытка - вручную обновлять этот код при изменении сервиса.

Я удивлен, что это не большая проблема, поскольку, похоже, нет никакого другого способа перехватить эти исключения в WP7 с использованием XNA, но я полагаю, что это просто больше говорит о том, сколько (== не так много) людей пытаются это сделать, чем что-либо еще.Если бы они просто создавали slsvcutil.exe методы генерации синхронизации, мы могли бы легко перехватить их в нашем собственном рабочем потоке, но, к сожалению, сгенерированный код использует потоки пула потоков без средств для перехвата исключений.

Чтобы справиться с этой ситуацией, используйте TargetInvocationException.Это приведет к перехвату исключения, когда сеть отключена или ваша служба недоступна.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top