Как обрабатывать ошибки
В этом разделе описаны основные шаги по созданию конфигурации маршрутизации с применением обработки ошибок. В данном примере сообщения перенаправляются в целевую конечную точку. Если сообщение не удается доставить из-за сбоя сети или канала связи (CommunicationException), оно повторно отправляется в альтернативную конечную точку.
Примечание.
Чтобы смоделировать сбой сети, в данном примере в целевую конечную точку включен неверный адрес. Направление сообщений в эту конечную точку будет завершаться ошибкой, поскольку ни одна служба не прослушивает указанный адрес.
Примечание.
Хотя пример, приведенный в данном разделе, специально не затрагивает параметры времени ожидания, при обработке ошибок их тоже нужно учитывать. При возникновении ошибок клиент получает ответ с дополнительной задержкой. Это происходит потому, что служба маршрутизации получает ошибку и пытается отправить сообщение в резервную конечную точку. Если значения времени ожидания, связанные с основной и резервной целевыми конечными точками, велики, клиент может столкнуться с длительной задержкой, вызванной тем, что до успешной отправки сообщение может безрезультатно направляться в разные конечные точки из резервного списка.
Поскольку служба маршрутизации может столкнуться с наибольшей задержкой, равной сумме значений времени ожидания для всех конечных точек, связанных с фильтром, рекомендуется соответствующим образом увеличить значение времени ожидания на клиенте.
Реализация обработки ошибок
Создайте базовую конфигурацию службы маршрутизации, указав конечную точку службы, предоставленную службой. В следующем примере определяется отдельная конечная точка службы, которая используется для получения сообщений. Также будут определены конечные точки клиента, которые используются для отправки сообщений - deadDestination и realDestination. Конечная точка deadDestination содержит адрес, который не ссылается на работающую службу и используется для моделирования сбоя сети при отправке сообщений в эту конечную точку.
<services> <service behaviorConfiguration="routingConfiguration" name="System.ServiceModel.Routing.RoutingService"> <host> <baseAddresses> <add baseAddress="http://localhost/routingservice/" /> </baseAddresses> </host> <!-- Create the Routing Service endpoint --> <endpoint address="router" binding="basicHttpBinding" name="RoutingServiceEndpoint" contract="System.ServiceModel.Routing.IRequestReplyRouter" /> </service> </services> <!-- Create the destination endpoints that we want to send to --> <client> <!-- Create a dummy endpoint that we know will be down --> <endpoint name="deadDestination" address="net.tcp://localhost:9090/servicemodelsamples/fakeDestination" binding="netTcpBinding" contract="*" /> <!-- Now create the real service endpoint --> <endpoint name="realDestination" address="net.tcp://localhost:8080/servicemodelsamples/service" binding="netTcpBinding" contract="*" /> </client>
Определите фильтры, используемые для маршрутизации сообщений до конечных точек назначения. В данном примере фильтр MatchAll используется для соответствия всем сообщениям, полученным службой маршрутизации.
<filters> <!-- Create a MatchAll filter which will catch all messages --> <filter name="MatchAllFilter1" filterType="MatchAll" /> </filters>
Задайте список резервных конечных точек, в которые сообщение отправляется в случае сбоя сети или канала связи при отправке сообщения в основную целевую конечную точку. В следующем примере задается резервный список с одной конечной точкой, хотя он может содержать несколько конечных точек.
Если в резервном списке содержится несколько конечных точек, то при возникновении сбоя сети или канала связи служба маршрутизации попытается отправить сообщение в первую из них. Если при отправке сообщения в эту точку возникает сбой сети или канала связи, служба маршрутизации попытается отправить сообщение в следующую конечную точку в списке. Служба продолжает отправлять сообщение в каждую из резервных конечных точек в списке до успешной отправки сообщения, или до получения от всех точек сообщения об ошибке сети или канала связи, или до получения от конечной точки сообщения об ошибке, не связанной с сетью или каналом связи, после отправки сообщения.
<backupLists> <backupList name="backupEndpointList"> <add endpointName="realDestination" /> </backupList> </backupLists>
Задайте таблицу фильтра, сопоставляющую фильтр с конечной точкой deadDestination и списком резервных конечных точек. Служба маршрутизации сначала попытается отправить сообщение в целевую конечную точку, сопоставленную с фильтром. Поскольку конечная точка deadDestination содержит адрес, не ссылающийся на работающую службу, эта попытка приведет к ошибке сети. Затем служба маршрутизации пытается отправить сообщение в конечную точку, указанную в backupEndpointList.
<filterTables> <!-- Set up the Routing Service's Message Filter Table --> <filterTable name="filterTable1"> <!-- Add an entity that maps the MatchAllMessageFilter to the dead destination --> <!-- If that endpoint is down, tell the Routing Service to try the endpoints --> <!-- Listed in the backupEndpointList --> <add filterName="MatchAllFilter1" endpointName="deadDestination" backupList="backupEndpointList"/> </filterTable> </filterTables>
Для оценки входящих сообщений с помощью фильтра, содержащегося в таблице фильтров, необходимо сопоставить таблицу фильтров с конечными точками службы при помощи поведения маршрутизации. В следующем примере показано связывание "filterTable1" с конечными точками службы.
<behaviors> <serviceBehaviors> <!-- Set up the Routing Behavior --> <behavior name="routingConfiguration"> <routing filterTableName="filterTable1" /> </behavior> </serviceBehaviors> </behaviors>
Пример
Ниже приведен полный список файла конфигурации:
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright (c) Microsoft Corporation. All Rights Reserved. -->
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="routingConfiguration"
name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost/routingservice/" />
</baseAddresses>
</host>
<!-- Create the Routing Service endpoint -->
<endpoint address="router"
binding="basicHttpBinding"
name="RoutingServiceEndpoint"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<!-- Set up the Routing Behavior -->
<behavior name="routingConfiguration">
<routing filterTableName="filterTable1" />
</behavior>
</serviceBehaviors>
</behaviors>
<!-- Create the destination endpoints that we want to send to -->
<client>
<!-- Create a dummy endpoint that we know will be down -->
<endpoint name="deadDestination"
address="net.tcp://localhost:9090/servicemodelsamples/fakeDestination"
binding="netTcpBinding"
contract="*" />
<!-- Now create the real service endpoint -->
<endpoint name="realDestination"
address="net.tcp://localhost:8080/servicemodelsamples/service"
binding="netTcpBinding"
contract="*" />
</client>
<routing>
<filters>
<!-- Create a MatchAll filter which will catch all messages -->
<filter name="MatchAllFilter1" filterType="MatchAll" />
</filters>
<filterTables>
<!-- Set up the Routing Service's Message Filter Table -->
<filterTable name="filterTable1">
<!-- Add an entry that maps the MatchAllMessageFilter to the dead destination -->
<!-- If that endpoint is down, tell the Routing Service to try the endpoints -->
<!-- Listed in the backupEndpointList -->
<add filterName="MatchAllFilter1" endpointName="deadDestination" backupList="backupEndpointList"/>
</filterTable>
</filterTables>
<!-- Create the backup endpoint list -->
<backupLists>
<backupList name="backupEndpointList">
<add endpointName="realDestination" />
</backupList>
</backupLists>
</routing>
</system.serviceModel>
</configuration>