Что такое System.ServiceModel.Diagnostics.CallbackException и почему я не могу с этим справиться? - PullRequest
6 голосов
/ 12 февраля 2010

В моем клиентском классе 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 ]

4 голосов
/ 16 февраля 2010

Как оказалось, 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 &lt;serviceDebug&gt; 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>
2 голосов
/ 16 февраля 2010

Вы видите System.ServiceModel.Diagnostics.CallbackException, поскольку на сервере происходит исключение. Поскольку исключение происходит за пределами домена клиентского приложения, возможно, оно относится к типу, к которому клиент не имеет доступа. Механизм обратного вызова обрабатывает это путем генерации CallbackException, который вы видите. Это похоже на System.TypeInitializationException, который генерируется при возникновении необработанного исключения при доступе к статическому члену. Если вы пытаетесь обработать это изящно, вы можете обработать исключение на стороне сервера и закрыть сокет, что впоследствии вызовет исключение на клиенте, которое может быть обработано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...