#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 { }
Комментариев нет:
Отправить комментарий