Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Технология WCF.docx
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
471 Кб
Скачать
☆

Контракты ошибок

Во всех реальных приложениях иногда происходят ошибки. Серивисы WCF не являются исключением. Давайте же рассмотрим, что происходит, если в WCF-сервисе произойдет ошибка. Для этого добавим в него еще один метод, осуществляющий целочисленное деление:

[OperationContract]

int Divide(int x, int y);

Обновим код клиента и посмотрим, что происходит, если в качестве делителя передать 0:

int divisionResult;

try

{

divisionResult = client.Divide(1, 0);

}

catch (Exception ex)

{ }

divisionResult = client.Divide(2, 1);

Как и следовало ожидать, на стороне клиента возникает исключение. Но это пол беды. Вы можете убедиться, что вызов любого другого метода клиента после получения исключения так же приводит к новому исключению. Клиент пришел в неработоспособное состояние. Чтобы продолжить работу нужно создать новый объект клиента. Данное поведение вызвано следующими причинами. На самом деле клиент ничего не знает о том, как реализован сервис. Возможно, что возникшая на сервисе ошибка привела к его полной неработоспособности. Именно поэтому по умолчанию продолжение работы клиента невозможно. Задача сервиса сообщать клиенту о том, что произошедшая ошибка не является фатальной и клиент может продолжить работу. Выполняется это с помощью контракта ошибок.

Контракт ошибок определяется очень просто. Нужно просто добавить к методу контрактного интерфейса один или несколько аттрибутов FaultContract:

[OperationContract]

[FaultContract(typeof(string))]

int Divide(int x, int y);

В качестве параметра этому аттрибуту передается тип информации об ошибке, которая будет возвращена клиенту. Не удивляйтесь, в качестве этого типа можно использовать что угодно, а не только исключения. Хотя, конечно, они используются здесь наиболее часто.

Последней тонкостью здесь является возбуждение самого исключения на стороне сервиса. Чтобы все работало как нужно, это необходимо выполнить особенным образом:

public int Divide(int x, int y)

{

if (y == 0)

throw new FaultException<string>("Can't divide by zero");

return x / y;

}

Для возбуждения исключения нужно использовать класс FaultException. Это generic-класс, в качестве параметра которому должен передаваться именно тот тип, который указан в аттрибуте FaultContract. Если вы используете какой-либо другой тип, то для сервиса ничего не изменится, но клиент останется в неработоспособном состоянии.

Попробуем, как теперь работает клиент. Как видите, теперь он сохраняет работоспособность, несмотря на ошибку, возникшую на стороне сервиса. Что, собственно, нам и требовалось.

Отладка системы wcf

К сожалению, ошибки могут происходить не только в вашем коде, но и в коде классов WCF. Существует множество настроек, изменяющих поведение вашего сервиса и клиента. В то же время необходимо поддерживать эквивалентность настроек привязки и контракта данных на сервере и клиенте. В случае, если взаимодействие этих частей почему-либо не происходит, необходимо узнать причину. Проблема в том, что источник ошибки обычно находится не в вашем коде, в внутри библиотек WCF. Хорошей новостью является то, что существует механизм, позволяющий увидеть, что же происходит внутри.

Сделать это очень просто. Нужно добавить в конфигурационный файл сервиса следующие строки:

<system.serviceModel>

<diagnostics>

<messageLogging

logEntireMessage="true"

logMalformedMessages="true"

logMessagesAtServiceLevel="true"

logMessagesAtTransportLevel="true"/>

</diagnostics>

…

</system.serviceModel>

<system.diagnostics>

<sources>

<source name="System.ServiceModel" switchValue="Verbose">

<listeners>

<clear />

<add initializeData="C:\TraceLog.svclog"

type="System.Diagnostics.XmlWriterTraceListener"

name="ServiceModel Listener" />

</listeners>

</source>

</sources>

</system.diagnostics>

Как видите, включение записи информации о функционировании системы WCF состоит из двух частей: включения элемента diagnostics в настройки WCF и добавления TraceListener. Элемент diagnostics включает в себя единственный элемент messageLogging, который указывает, какая именно информация должна сохраняться в лог. Можно сохранять 3 типа сообщений: поврежденные сообщения logMalformedMessages, сообщения транспортного уровня logMessagesAtTransportLevel и сообщения уровня сервиса logMessagesAtServiceLevel.

Если вы дадите вашему файлу лога расширение svclog, то этот файл можно будет открыть с помощью специального просмотрщика логов сервисов:

Это приложение позволяет в удобной форме просмотреть события, происходившие в системе классов WCF, обнаружить ошибки и их причины.