Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.145.15.1] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте. Я начал учить C# и WCF неделю назад, отсюда такие глупые вопросы:
Предположим, есть некий WCF сервис [ServiceContract] public interface IService { [OperationContract] void Method1(); [OperationContract] //... //... //... } и клиент этого сервиса void Main() { ServiceClient Client = new ServiceClient(); //... } Во избежание вылетов вызываю методы в блоке try 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 и не потерять стабильность? |
Сообщ.
#3
,
|
|
|
Spawn.NET
Так и знал, что мне кинут именно эту ссылку. Это не то. В статье написано о том, как в клиенте обрабатывать ошибки, возникающие на сервере. А мне всего-то надо, чтобы клиент не падал с ошибкой, если по каким-то причинам не удалось подключиться к серверу. Как вариант - вызывать все методы сервиса в отдельных блоках try-catch. Но, повторюсь, если методов много, код получается некрасивый (одни try-catch). Других вариантов нет? |
Сообщ.
#4
,
|
|
|
То ли я чего-то не понял, то ли одно из двух...
Чем тебе не по нутру вспомогательный метод, через который можно будет пропускать все методы, аля public void DoAction(Action act) { try { act(); } catch {} } В статье красиво написаны подобные "помощники". |
Сообщ.
#5
,
|
|
|
Spawn.NET
Тоже не вариант. Не все же методы сервиса имеют тип void. А для каждого типа делать свой DoAction - еще хуже, чем куча try-catch. |
Сообщ.
#6
,
|
|
|
GoldenJoe, Generic в "зубы".
private T DoAction<T>(Func<T> act) { return act(); } |
Сообщ.
#7
,
|
|
|
Spawn.NET
Про generic не знал, спасибо (в шарпе новичек же). Один минус только - придется реализовывать DoAction в каждом классе (ведь я вызываю методы сервиса не только в Main). |
Сообщ.
#8
,
|
|
|
Цитата GoldenJoe @ Один минус только - придется реализовывать DoAction в каждом классе (ведь я вызываю методы сервиса не только в Main). сделай static метод и вызывай откуда угодно public class Program { public static T DoAction<T>(Func<T> act) { return act(); } } public class Program2 { private void Test() { Program.DoAction<bool>( ... ); } } |
Сообщ.
#9
,
|
|
|
Spawn.NET
Невозможно получить аргумент типа для метода '[имя проекта].App.DoAction<T>(System.Func<T>)' из данных использования. Попробуйте указать аргументы типа явным образом. (класс называется App, ибо WPF, а не WinForms) Добавлено Такая ошибка возникает, когда я вызываю App.DoAction(Client.SomeMethod([параметры])); |
Сообщ.
#10
,
|
|
|
Цитата Такая ошибка возникает, когда я вызываю App.DoAction(Client.SomeMethod([параметры])); App.DoAction<T>(Client.SomeMethod([параметры])); где T возвращаемый тип |
Сообщ.
#11
,
|
|
|
GoldenJoe, без возвращаемого типа (ну, или с типом void) - Action<T1,T2,...,TN>, где TN - типы параметров. С возвращаемым типом - Func, где последний T - возвращаемый тип, все предшествующие - типы параметров.
Action и Func это всего лишь делегаты, которые можешь насоздавать сам, если, например, потребуется больше 4-х параметров в Action или Func. |
Сообщ.
#12
,
|
|
|
Наиболее подходящий перегруженный метод для '[неважно].App.DoAction<bool>(System.Func<bool>)' имеет несколько недопустимых аргументов. Подучить мне надо шарп видимо.
|
Сообщ.
#14
,
|
|
|
Spawn.NET
Сделал так public static T DoAction<T>(Func<T> action) { try { return action(); } catch (Exception ex) { //... } } Если метод сервиса не принимает параметры - все ок. Я так понял, если все-таки метод принимает параметры, надо наплодить еще DoAction'ов: с Func<T, T> для 1 параметра, с Func<T, T, T> для 2... Или я не так понял? |
Сообщ.
#15
,
|
|
|
В зависимости от типов параметров - да, хотя я бы скорее всего передавал бы массив параметров типа object, а там уж разбирался что к чему, чтобы много методов не плодить.
|
Сообщ.
#16
,
|
|
|
Можно не плодить, для этого можно использовать анонимный делигат:
static bool SaveCall(Func<bool> _func) { try { return _func(); } catch (System.Exception ex) { return false; } } Вызывать так: TestClass _testClient = new TestClass(); var _result = SaveCall(delegate() { _testClient.SameMethod0(); return true; }); |
Сообщ.
#17
,
|
|
|
maxim84_, вопрос был про метод с несколькими параметрами разных типов...
|
Сообщ.
#18
,
|
|
|
Цитата maxim84_, вопрос был про метод с несколькими параметрами разных типов... все тоже самое: 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" }; } } TestData _ReturnObject = null; string _argForSameMethod1 = "adsadsa"; _result = SaveCall(delegate() { _ReturnObject = _testClient.SameMethod1(_argForSameMethod1, 100); return true; }); |
Сообщ.
#19
,
|
|
|
А, ну отдельный класс возвращать, тогда да
|
Сообщ.
#20
,
|
|
|
Вообще-то это для демонстрации..
|
Сообщ.
#21
,
|
|
|
Как приду домой, попробую это
_result = SaveCall(delegate() { _ReturnObject = _testClient.SameMethod1(_argForSameMethod1, 100); return true; }); А просто засунуть весь метод Main/App_Startup в блок try/catch не вариант? Код вроде будет медленнее выполняться, верно? |
Сообщ.
#22
,
|
|
|
Всё через Try...Catch точно пускать не советую...
У клиента в классе Application вроде есть система отлова необработанных исключений, лучше её задействовать. |
Сообщ.
#23
,
|
|
|
я вообще не очень пойму проблему...Да, есть какой-то Wcf сервис, методы которого очевидно не безопасные. И есть некий внешний код, который юзает методы сервиса. Ну так может и обернуть этот клиент в безопасную обертку? тогда во внешнем коде не будут мозолить глаза try...catch...Хотя, куда без них ))
P.S. всеравно не пойму проблему |
Сообщ.
#24
,
|
|
|
Цитата maxim84_ @ Ну так может и обернуть этот клиент в безопасную обертку? То есть создать вспомогательный класс вроде этого 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 строчек будут повторяться десятки раз, я ж не холлоуворд сервис пишу) |
Сообщ.
#25
,
|
|
|
Цитата GoldenJoe @ А вот это уже интересно. http://msdn.microsoft.com/ru-ru/library/system.windows.forms.application.threadexception.aspx |
Сообщ.
#26
,
|
|
|
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; }); |
Сообщ.
#27
,
|
|
|
GoldenJoe, в WPF аналог - System.Windows.Application.DispatcherUnhandledException он экземплярный, а не статичный, как в Winforms, так что в Application.Current будет.
|
Сообщ.
#28
,
|
|
|
Spawn.NET, огромное спасибо! Все работает! Лови плюс.
P.S. в C# есть есть некий оператор, позволяющий узнать, например, что некоторый экземпляр класса Exception является CommunicationException. Точно есть, но что-то не гуглится. Добавлено Как все просто оказывается. if (ex is CommunicationException) { //... } Всем спасибо, от try-catch избавился. Вопрос решен. |