Что такое System.ServiceModel.Diagnostics.CallbackException и почему я не могу справиться с этим?
В моем классе клиента WCF я обрабатываю Faulted()
событие, так что если удаленная служба выдает исключение и выходит из строя канала, я все равно могу по крайней мере грациозно отключить его. Вот мой код:
protected void RemoteDataRetriever_Faulted(object sender, EventArgs e)
{
(sender as ICommunicationObject).Abort();
this.Dispose();
throw new ChannelTerminatedException("The remote service threw an unhandled exception and as a result the channel has been closed.");
}
Так что я ожидаю, что клиент может обрабатывать ChannelTerminatedException
что я бросил вручную и отправил сообщение пользователю и т. д. Вместо этого мое исключение заключено в System.ServiceModel.Diagnostics.CallbackException
, Хорошо. За исключением вот этого подвоха: это CallbackException не существует в библиотеке ServiceModel, и, похоже, у меня нет никакого способа его обработать, кроме как в качестве общего Exception
, что мне не подходит для моих юнит-тестов. Какого черта здесь происходит? Можно ли как-то отключить это и выдать исключение, которое я изначально хотел?
2 ответа
Как выясняется, System.ServiceModel.Diagnostics.CallbackException
является внутренним классом, встроенным в небольшую известную сборку под названием "%SystemRoot%\Microsoft.net\Framework\v3.0\Windows Communication Foundation\SMDiagnostics.dll", которая сама содержит только внутренние классы. Ну, это воняет, потому что это означает, что мы никогда не сможем поймать это исключение. Однако я смог найти класс / метод, который создает вышеупомянутое исключение (System.ServiceModel.Diagnostics.ExceptionUtility.ThrowHelperCallback(Exception innerException)), и обнаружил, что он вызывается виртуальным методом OnFapted() внутри CommunicationObject. Так что теоретически любой класс, производный от CommunicationObject (извините ClientBase<T>
) может переопределить этот метод и сказать ему не вызывать ThrowHelperCallback(). Это означает, что единственными жизнеспособными кандидатами являются классы, производные от ChannelFactoryBase<T>
, Теоретически я мог бы реализовать свою собственную фабрику пользовательских каналов, которая подавляет раздражающее CallbackException, но на данный момент это слишком много работы, поэтому я думаю, мне просто придется с этим справиться.
РЕДАКТИРОВАТЬ: @Jeremy - Если я проверяю конверт SOAP, возвращающийся по проводам, я обнаруживаю, что он дает мне общую ошибку, как и ожидалось, которая указывает на то, что CallbackException НЕ сериализуется и, следовательно, НЕ генерируется на сервере.
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Receiver</s:Value>
<s:Subcode>
<s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.</s:Text>
</s:Reason>
</s:Fault>
</s:Body>
Вы видите System.ServiceModel.Diagnostics.CallbackException
потому что на сервере происходит исключение. Поскольку исключение происходит за пределами домена клиентского приложения, возможно, оно относится к типу, к которому клиент не имеет доступа. Механизм обратного вызова обрабатывает это путем генерации CallbackException, которое вы видите. Это похоже на System.TypeInitializationException
это происходит, когда происходит необработанное исключение при доступе к статическому члену. Если вы пытаетесь обработать это изящно, вы можете обработать исключение на стороне сервера и закрыть сокет, что впоследствии вызовет исключение на клиенте, которое может быть обработано.