Declaration of VAR

and some other stuff

WS-Addressing в WCF

2015-05-01 21:03:41 +0300

2015-05-01 21:03:41 +0300 | Comments

Сервис на WCF поддерживает WS-Addressing, то есть способен писать и читать в заголовке поле ReplyTo, в котором содержится адрес для ответа.

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

В общем-то, ответ дан уже тут: How do I use WS-Addressing in WCF and set the wsa:replyto header, но мне этого в тот момент не хватило.

Итак, у нас есть WCF-сервис. И сразу же ограничение: его Binding должен поддерживать спецификацию WS-Addressing, то есть, например, BasicHttpBinding не подойдёт, а вот WSHttpBinding - вполне. Напомню, что Binding задаётся при создании сервиса.

И мы пишем клиент, который будет отправлять асинхронные запросы в этот сервис, причём нам нужно, чтобы сервис отвечал на определённый адрес, который может меняться (например, будет ещё несколько клиентов, и каждому нужны будут ответы на какой-то другой адрес). Поэтому на стороне сервиса мы не можем зашить определённый адрес для ответа. Для этого и предназначена спецификация WS-Addressing - в заголовке запроса, в специальном поле ReplyTo, записывается адрес, на который требуется отправить ответ.

Итак, ссылку на сервис в клиент мы добавили, сгенерировались нужные классы, в конфиг записались необходимые секции. Вызываем веб-метод и пишем в заголовок адрес для ответа:

SomeService.ServicesomeClient someClient = new SomeService.ServicesomeClient("WSHttpBinding_IServiceSome"); // это имя binding'а из конфига
using (OperationContextScope scope = new OperationContextScope(someClient.InnerChannel)) // вот где зарыты заголовки запроса
{
    OperationContext.Current.OutgoingMessageHeaders.ReplyTo = new EndpointAddress("http://some.domain/service.asmx/result");
    // и всё, а дальше вызываем уже метод сервиса
    someClient.request("ololo");
}

Теперь на стороне сервиса можно читать это поле в заголовке:

// веб-метод, который вызывается выше в клиенте (точнее, реализация интерфейса)
public void request(string requestContent)
{
    // читаем адрес для ответа из заголовка
    string replyto = OperationContext.Current.IncomingMessageHeaders.ReplyTo.ToString();
    // и вот в строке replyto лежит http://some.domen/service.asmx/result
}