#c_sharp #wcf #nat
Есть служба WCF, она хостится на порту 8888.
При использовании NAT
outside 8888, inside 8888 - проходит отлично.
outside 2145, inside 8888 - проходит с ошибкой.
outside 5416, inside 8888 - проходит с ошибкой.
Т.е., если использовать одинаковые порты на входе и выходе запросы проходят.
Если они разные, тогда нет.
Служба
Байндинг службы
private static WSHttpBinding Setbinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
return binding;
}
Клиент
Код запроса
int PortNumber =2145;//или 5416 или 8888
client = new PServiceClient(GetBinding(),
new EndpointAddress(string.Format("http://{0}:{1}/PService/", "168.211.65.22",
PortNumber)));
...
//Проверка коннекта
bool res = client.Connect();
Байндинг клиента
private WSHttpBinding GetBinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
timeout = TimeOut.GetTimeOut();
return binding;
}
Почему у меня не работают корректно запросы к службе при использовании NAT?
Ответы
Ответ 1
Вы используете WSHttpBinding - а эта привязка подразумевает использование стандарта WS‑Addressing, который в свою очередь передает адрес принимающей стороны в заголовке To. Честно говоря, я не знаю зачем вообще в веб-сервисах, где отправитель и получатель сообщения всегда известны, использовать WS‑Addressing. Выглядит как глупость, и именно из-за нее SOAP считают довольно "тяжелым" протоколом. Поэтому самый простой способ - отказаться от WSHttpBinding и перейти на BasicHttpBinding, там такой проблемы нет. Если же вам требуется именно WSHttpBinding - то есть три пути. Самый правильный с точки зрения стандартов - рассказать серверу какой у него реальный адрес: var binding = new WSHttpBinding(); var internalUri = new Uri("http://192.168.1.10:8888/PService/"); var externalUri = new Uri("http://168.211.65.22:2145/PService/"); ServiceHost host = new ServiceHost(foo); host.AddServiceEndpoint(typeof(IFoo), binding, internalUri); host.AddServiceEndpoint(typeof(IFoo), binding, address: externalUri, listenUri: internalUri); Я добавил две конечные точки чтобы сервер мог принимать как прямые запросы так и запросы через NAT. Но хардкодить адреса - не лучшая идея, все же такие вещи лучше выносить в код:Тут главное - не перепутайте, address - это то что сервер будет ждать в заголовке To, сюда попадает тот адрес который видит клиент; listenUri же - этот тот адрес который реально слушает сервер. Альтернативный вариант - обучить клиент передавать правильные заголовки. Этот вариант не очень хороший, поскольку раскрывает перед клиентом внутреннюю структуру сети сервера. Но для полноты картины я его тоже приведу. var binding = new WSHttpBinding(); var internalUri = new Uri("http://192.168.1.10:8888/PService/"); var externalUri = new Uri("http://168.211.65.22:2145/PService/"); var client = new FooClient(binding, new EndpointAddress(internalUri)); client.Endpoint.EndpointBehaviors.Add(new ClientViaBehavior(externalUri)); Как я уже писал, адреса предпочтительнее задавать в конфиге. Для клиента это делается так: Как видно, уже чуть сложнее чем для сервера но все еще ничего страшного. Также допустим смешанный вариант. Дело в том, что от адреса конечной точки совершенно не требуется чтобы он был настоящим http-адресом! Все реальные http-адреса указываются в атрибутах listenUri и viaUri, к адресу же главное требование - совпадение у клиента и у сервера. А значит, туда можно написать любой uri, например какой-нибудь urn:local:my-cool-web-service (такой адрес обычно называют логическим адресом сервиса). Вот пример конфигов для сервера и клиента с настроенным логическим адресом: Достоинство этого варианта - ни клиент ни сервер ничего не знают о деталях трансляции адресов. Недостаток же этого варианта заключается в том, что если вы покажите такой конфиг стороннему разработчику, он может, э-э-э... слегка удивиться такому решению. Наконец, самый последний вариант. Самый простой, но костыль. Можно вовсе отключить проверку адреса на стороне сервера: [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)] class Foo : IFoo { }
Комментариев нет:
Отправить комментарий