- •Технология wcf Оглавление
- •Введение
- •Создание wcf-сервиса
- •Создание интерфейса сервиса
- •Концепция “abc”
- •Хосты сервисов wcf
- •Развертывание wcf-сервиса в консольном приложении
- •Настройка конфигурационного файла
- •Публикация метаданных сервиса
- •Развертывание wcf-сервиса в iis
- •Создание клиента
- •Контракты данных
- •Контракты ошибок
- •Отладка системы wcf
- •Безопасность wcf
- •Заключение
Контракты ошибок
Во всех реальных приложениях иногда происходят ошибки. Серивисы 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, обнаружить ошибки и их причины.
