Здравствуйте, andyag, Вы писали:
A>Вот тут вот: https://msdn.microsoft.com/en-us/library/ms752208(v=vs.110).aspx пишут, что сервер должен кидать FaultException<T>, а клиент соответственно — ловить FaultException<T>. А нет ли у WCF из коробки какого-то флажка, чтобы вместо FaultException можно было кидать и ловить свой тип исключений — MyVeryCustomApiException и его наследников? Понятно, что можно написать много кода и получить такое поведение, но интересует именно наличие решения из коробки. Из более-менее релевантного на той же странице нашлось "includeExceptionDetailInFaults", но оно это, конечно, не то.
Шибко много кода писать не надо.
вам надо реализовать IErrorHandler и привязать его к серверу + реализовать IClientMessageInspector на предмет анализа приходящих ошибок клиенту от севера. Инспектор нужно в свою очередь прикрутить к клиенту.
Здравствуйте, andyag, Вы писали:
A>Вот тут вот: https://msdn.microsoft.com/en-us/library/ms752208(v=vs.110).aspx пишут, что сервер должен кидать FaultException<T>, а клиент соответственно — ловить FaultException<T>. А нет ли у WCF из коробки какого-то флажка, чтобы вместо FaultException можно было кидать и ловить свой тип исключений — MyVeryCustomApiException и его наследников? Понятно, что можно написать много кода и получить такое поведение, но интересует именно наличие решения из коробки. Из более-менее релевантного на той же странице нашлось "includeExceptionDetailInFaults", но оно это, конечно, не то.
На сколько я знаю нет.
А можете примерно описать, чего вам хочется добиться — может не так и много кода понадобится...
Здравствуйте, andyag, Вы писали:
A>Как-то так.
Ну нечто подобное я и предполагал... Логично
В общем, "из коробки" такое работать действительно не будет.
Причем, основная проблема мне видится в том, что Exception, после раскрутки стека (т.е. когда его ловит инфраструктура WCF) не сериализуется стандартным WCF сериализатором.
В принципе, не так и сложно сделать некоторую доработку, чтобы получить желаемое вами поведение:
Добавить глобальный IErrorHandler — для перекладывания всех исключений (или тех, которые вы решите отправлять на клиента) в fault сообщение
На клиенте принять такое сообщение, достать исключение, восстановить и перевыбросить.
Вот
тут есть на первый взгляд вполне готовое решение, но, увы непроверенное.
Там для прокидывания используется NetDataContractSerializer (значит нужно будет для контрактов использовать shared-сборки), а на клиенте MessageInspector, который вычитывает детальную информацию из фолта и выбрасывает исключение. Все остальное там — behaviors, для добавления этих расширений.
У автора сделано для всех исключений вообще, но вы можете ограничиться только своей иерархией.
Сам я так не делал никогда, в первую очередь из-за необходимости "доработки" клиента, поэтому оценить решение не возьмусь. Но выглядит логично (по крайней мере я бы делал аналогично, будь такая задача нужна). Единственный вопрос в том как выбрасывать исключение на клиенте, чтобы не потерять информацию из исключения на сервере. Но тут я бы поступил примерно так:
Во все передаваемые на клиента исключения добавил некий CorrelationID (ErrorID), который заполнялся бы в момент генерации исключения
На сервере в том же обработчике записывал бы исключение в логи (явно выделяя ID, по которому потом нужно будет сопоставлять).
На клиенте выбрасывал бы заново, не обращая внимания, на то, что теряется тот же стек — главное, чтобы уцелело ID. Ну а потом бы уже сопоставлял ошибки на сервере и клиенте.
P.S. Да, на решение "из коробки" не тянет. Но, мне кажется из коробки такое вряд ли кто-то взялся бы делать.
Здравствуйте, andyag, Вы писали:
A>Вот тут вот: https://msdn.microsoft.com/en-us/library/ms752208(v=vs.110).aspx пишут, что сервер должен кидать FaultException<T>, а клиент соответственно — ловить FaultException<T>. А нет ли у WCF из коробки какого-то флажка, чтобы вместо FaultException можно было кидать и ловить свой тип исключений — MyVeryCustomApiException и его наследников? Понятно, что можно написать много кода и получить такое поведение, но интересует именно наличие решения из коробки. Из более-менее релевантного на той же странице нашлось "includeExceptionDetailInFaults", но оно это, конечно, не то.
А можете сказать — для чего это надо? Есть стандартное FaultException, в него можно включить все, что угодно. Если делать то, что хотите вы, то другой стороне, реализовывать которую могут другие люди (или поддерживать) придется закладываться на такое нестандартное поведение. Зачем?
Вот тут вот:
https://msdn.microsoft.com/en-us/library/ms752208(v=vs.110).aspx пишут, что сервер должен кидать FaultException<T>, а клиент соответственно — ловить FaultException<T>. А нет ли у WCF из коробки какого-то флажка, чтобы вместо FaultException можно было кидать и ловить свой тип исключений — MyVeryCustomApiException и его наследников? Понятно, что можно написать много кода и получить такое поведение, но интересует именно наличие решения из коробки. Из более-менее релевантного на той же странице нашлось "includeExceptionDetailInFaults", но оно это, конечно, не то.
Здравствуйте, Михаил Романов, Вы писали:
МР>Здравствуйте, andyag, Вы писали:
A>>Вот тут вот: https://msdn.microsoft.com/en-us/library/ms752208(v=vs.110).aspx пишут, что сервер должен кидать FaultException<T>, а клиент соответственно — ловить FaultException<T>. А нет ли у WCF из коробки какого-то флажка, чтобы вместо FaultException можно было кидать и ловить свой тип исключений — MyVeryCustomApiException и его наследников? Понятно, что можно написать много кода и получить такое поведение, но интересует именно наличие решения из коробки. Из более-менее релевантного на той же странице нашлось "includeExceptionDetailInFaults", но оно это, конечно, не то.
МР>На сколько я знаю нет.
МР>А можете примерно описать, чего вам хочется добиться — может не так и много кода понадобится...
[ServiceContract]
interface ICalculator
{
[OperationContract]
[SuperMegaFaultContract(DivisionByZeroException)] // <-----------
int Divide(int a, int b);
}
class ApiException : Exception {}
class DivisionByZeroException : ApiException {}
class Calculator : ICalculator
{
public int Divide(int a, int b)
{
throw new DivisionByZeroException(); // <----------- вот тут кидается
}
}
...
var calculator = channelFactory.GiveMe(typeof(ICalculator));
try
{
calculator.Divide(1, 0); // <--------- летит вот отсюда
Assert.Fail()
}
catch(DivisionByZeroException e) // <-----------
{
// ожидается, что попадём сюда
}
Как-то так.