На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> WCF клиент: обработка исключений
    Здравствуйте. Я начал учить C# и WCF неделю назад, отсюда такие глупые вопросы:
    Предположим, есть некий WCF сервис
    ExpandedWrap disabled
          [ServiceContract]
          public interface IService
          {
              [OperationContract]
              void Method1();
       
              [OperationContract]
              //...
              //...
              //...
          }

    и клиент этого сервиса
    ExpandedWrap disabled
      void Main()
      {
          ServiceClient Client = new ServiceClient();
          //...
      }

    Во избежание вылетов вызываю методы в блоке try
    ExpandedWrap disabled
      try
      {
          Client.Method1();
      }
      catch(Exception ex)
      {
          Client.Abort();
          MessageBox.Show(ex.ToString());
          Application.Current.Shutdown();
      }


    Если метод всего 1, блоки try-catch глаза не мозолят. А если их много (Client.Method1(), Client.Method2(), Client.Method3()...) и вызывать каждый в отдельном блоке try-catch, код выглядит просто ужасно. Можно выкинуть эти try-catch, но тогда клиент будет падать, если сервер "временно недоступен" или просто-напросто на компьютере клиента отсутствует подключение к интернету.
    То есть, если вызывать каждый метод в отдельном try-catch, получается стабильный, но ужасно НЕКРАСИВЫЙ код. А если без try-catch, соответственно красивый, но НЕСТАБИЛЬНЫЙ.
    Возможно ли избавиться от try-catch и не потерять стабильность?
      Читай про обработку ошибок в WCF, например, тут.
        Spawn.NET
        Так и знал, что мне кинут именно эту ссылку. Это не то. В статье написано о том, как в клиенте обрабатывать ошибки, возникающие на сервере. А мне всего-то надо, чтобы клиент не падал с ошибкой, если по каким-то причинам не удалось подключиться к серверу. Как вариант - вызывать все методы сервиса в отдельных блоках try-catch. Но, повторюсь, если методов много, код получается некрасивый (одни try-catch). Других вариантов нет?
          То ли я чего-то не понял, то ли одно из двух...
          Чем тебе не по нутру вспомогательный метод, через который можно будет пропускать все методы, аля
          ExpandedWrap disabled
            public void DoAction(Action act)
            {
                try
                {
                    act();
                }
                catch {}
            }

          В статье красиво написаны подобные "помощники".
            Spawn.NET
            Тоже не вариант. Не все же методы сервиса имеют тип void. А для каждого типа делать свой DoAction - еще хуже, чем куча try-catch.
              GoldenJoe, Generic в "зубы".
              ExpandedWrap disabled
                        private T DoAction<T>(Func<T> act)
                        {
                            return act();
                        }
                Spawn.NET
                Про generic не знал, спасибо (в шарпе новичек же).
                Один минус только - придется реализовывать DoAction в каждом классе (ведь я вызываю методы сервиса не только в Main).
                  Цитата GoldenJoe @
                  Один минус только - придется реализовывать DoAction в каждом классе (ведь я вызываю методы сервиса не только в Main).

                  сделай static метод и вызывай откуда угодно
                  ExpandedWrap disabled
                    public class Program
                    {
                            public static T DoAction<T>(Func<T> act)
                            {
                                return act();
                            }
                    }
                     
                    public class Program2
                    {
                            private void Test()
                            {
                                Program.DoAction<bool>( ... );
                            }
                    }
                    Spawn.NET
                    Невозможно получить аргумент типа для метода '[имя проекта].App.DoAction<T>(System.Func<T>)' из данных использования. Попробуйте указать аргументы типа явным образом.
                    (класс называется App, ибо WPF, а не WinForms)

                    Добавлено
                    Такая ошибка возникает, когда я вызываю App.DoAction(Client.SomeMethod([параметры]));
                      Цитата
                      Такая ошибка возникает, когда я вызываю App.DoAction(Client.SomeMethod([параметры]));


                      ExpandedWrap disabled
                        App.DoAction<T>(Client.SomeMethod([параметры]));


                      где T возвращаемый тип
                        GoldenJoe, без возвращаемого типа (ну, или с типом void) - Action<T1,T2,...,TN>, где TN - типы параметров. С возвращаемым типом - Func, где последний T - возвращаемый тип, все предшествующие - типы параметров.
                        Action и Func это всего лишь делегаты, которые можешь насоздавать сам, если, например, потребуется больше 4-х параметров в Action или Func.
                          Наиболее подходящий перегруженный метод для '[неважно].App.DoAction<bool>(System.Func<bool>)' имеет несколько недопустимых аргументов. Подучить мне надо шарп видимо.
                            GoldenJoe, начни отсюда и далее по ссылкам.
                              Spawn.NET
                              Сделал так
                              ExpandedWrap disabled
                                public static T DoAction<T>(Func<T> action)
                                {
                                    try
                                    {
                                        return action();
                                    }
                                    catch (Exception ex)
                                    {
                                        //...  
                                    }
                                }

                              Если метод сервиса не принимает параметры - все ок.
                              Я так понял, если все-таки метод принимает параметры, надо наплодить еще DoAction'ов: с Func<T, T> для 1 параметра, с Func<T, T, T> для 2...
                              Или я не так понял?
                                В зависимости от типов параметров - да, хотя я бы скорее всего передавал бы массив параметров типа object, а там уж разбирался что к чему, чтобы много методов не плодить.
                                  Можно не плодить, для этого можно использовать анонимный делигат:

                                  ExpandedWrap disabled
                                            static bool SaveCall(Func<bool> _func)
                                            {
                                                try
                                                {
                                                    return _func();
                                                }
                                                catch (System.Exception ex)
                                                {
                                                    return false;
                                                }
                                            }


                                  Вызывать так:
                                  ExpandedWrap disabled
                                               TestClass _testClient = new TestClass();
                                     
                                               var _result = SaveCall(delegate()
                                                {
                                                    _testClient.SameMethod0();
                                                    return true;
                                                });
                                    maxim84_, вопрос был про метод с несколькими параметрами разных типов...
                                      Цитата
                                      maxim84_, вопрос был про метод с несколькими параметрами разных типов...

                                      все тоже самое:

                                      ExpandedWrap disabled
                                            public class TestData
                                            {
                                                public string Name { get; set; }            
                                            }
                                         
                                            public class TestClass
                                            {
                                                public void SameMethod0()
                                                {
                                                    throw new Exception();
                                                }
                                         
                                                public TestData SameMethod1(string _arg, int _index)
                                                {
                                                    Console.WriteLine("Call method 'SameMethod1'. Arg = {0}, Index={1}", _arg, _index);
                                         
                                                    return new TestData()
                                                    {
                                                        Name = "From SameMethod"
                                                    };
                                                }
                                            }


                                      ExpandedWrap disabled
                                                    TestData _ReturnObject = null;
                                                    string _argForSameMethod1 = "adsadsa";
                                                    _result = SaveCall(delegate()
                                                    {
                                                        _ReturnObject = _testClient.SameMethod1(_argForSameMethod1, 100);
                                                        return true;
                                                    });
                                        А, ну отдельный класс возвращать, тогда да :)
                                          Вообще-то это для демонстрации..
                                            Как приду домой, попробую это
                                            ExpandedWrap disabled
                                              _result = SaveCall(delegate()
                                              {
                                                  _ReturnObject = _testClient.SameMethod1(_argForSameMethod1, 100);
                                                  return true;
                                              });


                                            А просто засунуть весь метод Main/App_Startup в блок try/catch не вариант? Код вроде будет медленнее выполняться, верно?
                                              Всё через Try...Catch точно пускать не советую...
                                              У клиента в классе Application вроде есть система отлова необработанных исключений, лучше её задействовать.
                                                я вообще не очень пойму проблему...Да, есть какой-то Wcf сервис, методы которого очевидно не безопасные. И есть некий внешний код, который юзает методы сервиса. Ну так может и обернуть этот клиент в безопасную обертку? тогда во внешнем коде не будут мозолить глаза try...catch...Хотя, куда без них ))

                                                P.S. всеравно не пойму проблему :)
                                                  Цитата maxim84_ @
                                                  Ну так может и обернуть этот клиент в безопасную обертку?

                                                  То есть создать вспомогательный класс вроде этого
                                                  ExpandedWrap disabled
                                                    public class Helper
                                                    {
                                                        private ServiceClient Client = new ServiceClient();
                                                     
                                                        public bool Method1()
                                                        {
                                                            try
                                                            {
                                                                return Client.Method1();
                                                            }
                                                            catch
                                                            {
                                                                //...
                                                            }
                                                        }
                                                    }

                                                  И так для каждого метода? Тоже не очень красивое решение.

                                                  Цитата Spawn.NET @
                                                  У клиента в классе Application вроде есть система отлова необработанных исключений, лучше её задействовать.

                                                  А вот это уже интересно.

                                                  Добавлено
                                                  Цитата maxim84_ @
                                                  всеравно не пойму проблему

                                                  Если повсюду try-catch - уже раздражает. Так еще в блоке catch у меня строк 5 кода, так надо. Получается еще и много повторяющегося кода (вот эти 5 строчек будут повторяться десятки раз, я ж не холлоуворд сервис пишу)
                                                    Цитата GoldenJoe @
                                                    А вот это уже интересно.

                                                    http://msdn.microsoft.com/ru-ru/library/system.windows.forms.application.threadexception.aspx
                                                      Spawn.NET, на эту статью уже натыкался. Только для Windows Forms. Я WPF юзаю, там этого нет. А мешать их вместе не рекомендуется.

                                                      Добавлено
                                                      Цитата GoldenJoe @
                                                      _result = SaveCall(delegate()
                                                      {
                                                      _ReturnObject = _testClient.SameMethod1(_argForSameMethod1, 100);
                                                      return true;
                                                      });

                                                      Работает, но хотелось бы еще попроще. Создать бы единый обработчик для CommunicationException, было бы очень хорошо (вместо try-catch для КАЖДОГО метода сервиса)

                                                      Добавлено
                                                      Или вместо
                                                      Цитата GoldenJoe @
                                                      _result = SaveCall(delegate()
                                                      {
                                                      _ReturnObject = _testClient.SameMethod1(_argForSameMethod1, 100);
                                                      return true;
                                                      });
                                                        GoldenJoe, в WPF аналог - System.Windows.Application.DispatcherUnhandledException он экземплярный, а не статичный, как в Winforms, так что в Application.Current будет.
                                                          Spawn.NET, огромное спасибо! Все работает! Лови плюс.

                                                          P.S. в C# есть есть некий оператор, позволяющий узнать, например, что некоторый экземпляр класса Exception является CommunicationException. Точно есть, но что-то не гуглится.

                                                          Добавлено
                                                          Как все просто оказывается.
                                                          ExpandedWrap disabled
                                                            if (ex is CommunicationException)
                                                            {
                                                                //...
                                                            }


                                                          Всем спасибо, от try-catch избавился. Вопрос решен.
                                                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                          0 пользователей:


                                                          Рейтинг@Mail.ru
                                                          [ Script execution time: 0,0698 ]   [ 16 queries used ]   [ Generated: 2.05.24, 22:16 GMT ]