Односторонние службы

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

Односторонний шаблон используется в следующих случаях.

  • Если клиент должен вызывать операции и не зависит от результата выполнения этих операций на уровне операций.

  • При использовании класса NetMsmqBinding или MsmqIntegrationBinding. (Дополнительные сведения об этом сценарии см. в разделе Очереди в WCF.)

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

Чтобы создать односторонний контракт службы, определите контракт службы, примените класс OperationContractAttribute к каждой из операций, и установите свойство IsOneWay равным true, как показано в следующем примере кода.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]  
public interface IOneWayCalculator  
{  
    [OperationContract(IsOneWay=true)]  
    void Add(double n1, double n2);  
    [OperationContract(IsOneWay = true)]  
    void Subtract(double n1, double n2);  
    [OperationContract(IsOneWay = true)]  
    void Multiply(double n1, double n2);  
    [OperationContract(IsOneWay = true)]  
    void Divide(double n1, double n2);  
}  

Полный пример см. в примере one-Way .

Блокировка клиентов с помощью односторонних операций

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

Например, если транспорту не удается найти конечную точку, исключение System.ServiceModel.EndpointNotFoundException будет создано без большой задержки. Однако также возможна ситуация, при которой службе по какой-либо причине не удается считать данные из сети, в результате чего операция отправки на стороне клиента не может быть завешена. В этих случаях, если превышается время Binding.SendTimeout привязки транспорта клиента, создается исключение System.TimeoutException - но не раньше истечения времени ожидания. Кроме того, службе может быть отправлено так много сообщений, что в какой-то момент служба больше не сможет их обрабатывать. В этом случае односторонний клиент также блокируется, пока служба не сможет обработать сообщения или пока не будет создано исключение.

Подобная блокировка также может происходить в том случае, если свойство ServiceBehaviorAttribute.ConcurrencyMode службы имеет значение Single, а привязка использует сеансы. В этом случае диспетчер принудительно упорядочивает входящие сообщения (требование сеансов), что не допускает чтения из сети следующего сообщения, пока служба не обработала предыдущее сообщение для этого сеанса. Клиент в этом случае также блокируется, но появление исключения зависит от того, успеет ли служба обработать ожидающие данные, пока не истечет установленное на стороне клиента время ожидания.

Можно частично ограничить эту проблему, поместив буфер между объектом клиента и операцией отправки транспорта клиента. Например, при использовании асинхронных вызовов или очереди сообщений в памяти объект клиента может быстро возвращать управление. Оба подхода могут расширить функциональность, но размер пула потоков и очереди сообщений по-прежнему накладывает ограничения.

Вместо этого рекомендуется изучить различные элементы управления службы и клиента и испытать различные сценарии работы приложения, чтобы определить наилучшую конфигурацию на каждой из сторон. Например, если использование сеансов блокирует обработку сообщений на стороне службы, можно установить для свойства ServiceBehaviorAttribute.InstanceContextMode значение PerCall, чтобы каждое сообщение обрабатывалось отдельным экземпляром службы, а также установить свойство ConcurrencyMode равным Multiple, чтобы одновременно распределять сообщения могло более одного потока. Еще одно возможное решение - увеличить квоты чтения привязок службы и клиента.

См. также