WCF, метаданные и BIGIP. Могу ли я указать правильный URL-адрес для элементов WSDL?
У нас есть служба WCF, размещенная на сервере ServerA, который является сервером без прямого доступа в Интернет и имеет маршрутизируемый IP-адрес вне Интернета.
Служба обслуживается BIGIP, который обрабатывает шифрование и дешифрование SSL и перенаправляет незашифрованный запрос на ServerA (в настоящий момент он НЕ выполняет балансировку нагрузки, но, вероятно, будет добавлен в будущем) на конкретный порт.
Это означает, что наши клиенты будут вызывать службу через https://www.ourdomain.com/ServiceUrl и получать доступ к нашей службе по http://severa:85/ServiceUrl через устройство BIGIP;
Когда мы просматриваем WSDL, опубликованный на https://www.ourdomain.com/ServiceUrl все адреса, содержащиеся в WSDL, основаны на базовом адресе http://severa:85/ServiceUrl.
Мы выяснили, что мы могли бы использовать настройку заголовков хоста, чтобы установить домен, но наша проблема в том, что, хотя это приведет к сортировке домена, мы все равно будем использовать неправильную схему - она будет использовать http://www.ourdomain.com/ServiceUrl пока нам нужно, чтобы он был https.
Кроме того - поскольку у нас есть другие службы (на основе asmx), размещенные на этом сервере, у нас были некоторые проблемы с настройкой заголовков хостов, и поэтому мы подумали, что можем избежать создания другого сайта на сервере (используя, скажем, порт 82) и установить заголовок хоста на этом; Теперь, помимо проблемы http / https, у нас есть проблема, поскольку WSDL содержит номер порта во всех URL-адресах, где BigIP работает через порт 443 (для SSL).
Есть ли более гибкое решение, чем реализация Host Headers? В идеале нам нужно сохранить гибкость и простоту поддержки.
Спасибо за любую помощь...
5 ответов
По сути, это проблема, состоящая из нескольких частей, которая включает в себя ряд отдельных решений, чтобы дать полный ответ. По сути, есть 3 проблемы с сидением за F5.
- Имя хоста конечной точки объявленной услуги.
- Имя хоста ссылок на схемы xsd:import, которые описывают контракт данных
- проблема http / https, которую вы описываете.
Изменение заголовков хоста, как вы нашли, решает 1 и 2 (вы можете подойти к этому другими способами, чем заголовки хоста, но здесь не нужно вдаваться в подробности). Номер 3 немного сложнее и требует больше кода (слишком много, чтобы вывести его сюда).
Краткий ответ: вам нужно написать ContractBehavior, который реализует как IContractBehavior, так и IWsdlExportExtension.
Важный бит, который необходимо реализовать, - это IWsdlExportExtension.ExportEndpoint. В этом методе вам нужно выполнить итерацию по всем расширениям WsdlPort, а когда вы найдете расширение типа SoapAddressBinding, вам нужно заменить свойство SoapAddressBinding.Location новым Uri, содержащим спецификатор протокола https. Вам также необходимо сделать аналогичные биты для адресов импорта xsd и ссылок схемы.
Если ваша служба также использует WS-адресацию, вам нужно выполнить нечто подобное для обработки дополнительных адресов, которые она записывает в wsdl.
Я основал код, который в итоге написал, на проекте WsdlExtras, доступном на CodePlex ( http://www.codeplex.com/WCFExtras/). Метод, используемый в WsdlExtras, обеспечивает отличную базу для любых дополнительных битов, которые вам, возможно, понадобится добавить в него (из памяти я не думаю, что он имел дело с битами WS-Addressing). Бит, который вы хотите посмотреть, это "Переопределить URL-адрес расположения SOAP".
Благодаря Марку Аллансону у меня был точно такой же сценарий, как и у Йосси Дахана, файл WCFExtras.dll работал для меня,
шаг 1. скачать файл WCFExtras.dll http://www.codeplex.com/WCFExtras/%29.
шаг 2. добавить ссылку на ваш проект.
шаг 3. не тратьте свое время на написание кода, как это предлагается в примере приложения сервера.
step4. Откройте файл web.config и введите следующий код:
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehaviorName" name="ServiceName">
<endpoint address="" behaviorConfiguration="ServiceEndpointBehaviorName" binding="basicHttpBinding" contract="IServiceName">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="ServiceEndpointBehaviorName">
<wsdlExtensions location="https://sslLoadBalancer/ServiceName.svc"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviorName">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!-- Declare that we have an extension called WSDL Extras-->
<add name="wsdlExtensions" type="WCFExtras.Wsdl.WsdlExtensionsConfig, WCFExtras, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
step5. Также важно отметить, что если вы добавите ссылку по этому URL "https://sslLoadBalancer/ServiceName.svc"
тогда это не будет работать, всегда не забывайте добавлять ссылку как: "https://sslLoadBalancer/ServiceName.svc?wsdl"
Таким образом, вы сможете добавить ссылку на ваше приложение.
Вот и все... если все еще не работает, то дайте мне знать, я вставлю полный файл web.config..
Спасибо
К вашему классу обслуживания добавьте атрибут:
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>
Это позволяет клиенту обращаться к сервису как https://..., но сервис должен быть размещен на http://.....
В файле web.config хоста службы элемент конечной точки должен иметь абсолютный URL-адрес в атрибуте адреса, который является общедоступным URL-адресом, который будет использоваться клиентом. В том же элементе конечной точки установите для атрибута listenUri абсолютный URL-адрес, который прослушивает хост службы. Способ определения абсолютного URI по умолчанию, который прослушивает хост, заключается в добавлении ссылки на службу в клиентском приложении, которая указывает на физический сервер, на котором размещена служба. У клиента web.config будет адрес службы. Затем я копирую это в атрибут listenUri в хосте web.config.
В своей конфигурации поведения службы добавьте элемент serviceMetaData с атрибутом httpGetEnabled = true
Так что у вас будет что-то вроде:
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior
</serviceBehaviors>
...
<services>
<service name="NamespaceQualifiedServiceClass" behavior="myBehavior" >
<endpoint address="https://www.sslloadbalancer.com" binding="someBinding" contract="IMyServiceInterface" listenUri="http://www.servicehost.com" ... />
</service>
</services>
Я не уверен, работает ли это с безопасностью сообщений или транспортной безопасностью. Для этого конкретного приложения учетные данные были переданы как часть DataContract, поэтому у нас был базовый режим безопасности HttpBinding = нет. Поскольку транспорт безопасен (для балансировщика нагрузки ssl), проблем с безопасностью не было.
Можно также оставить атрибут listenUri пустым, однако он должен присутствовать.
К сожалению, в WCF есть ошибка, когда базовый адрес импортированных схем в WSDL имеет базовый адрес listenUri, а не общедоступный базовый адрес (тот, который настроен с использованием атрибута адреса конечной точки). Чтобы обойти эту проблему, вам нужно создать реализацию IWsdlExportExtension, которая напрямую переносит импортированные схемы в документ WSDL и удаляет импорт. Пример этого представлен здесь http://winterdom.com/2006/10/inlinexsdinwsdlwithwcf. Кроме того, вы можете получить пример класса, наследуемый от BehaviorExtensionElement, и дополнить два новых метода:
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(InlineXsdInWsdlBehavior)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New InlineXsdInWsdlBehavior()
End Function
Это позволит вам добавить поведение расширения в файл.config и добавить поведение, используя конфигурацию, а не создавать фабрику сервисов.
под элемент конфигурации system.servicemodel добавьте:
<endpointBehaviors>
<behavior name="SSLLoadBalancerBehavior">
<flattenXsdImports/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!--The full assembly name must be specified in the type attribute as of WCF 3.5sp1-->
<add name="flattenXsdImports" type="Org.ServiceModel.Description.FlattenXsdImportsEndpointBehavior, Org.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
А затем сослаться на новое поведение конечной точки в вашей конфигурации конечной точки с помощью атрибута поведение Configuration
<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">
Я получил отличный совет, что установка атрибута адреса в конечной точке на URL, который вы хотите отобразить в WSDL, а затем добавление атрибута listenUri в конечную точку с фактическим Uri для прослушивания, сделает свое дело.
URL-адрес на тестовой странице не изменяется (т. Е. Он по-прежнему будет отображать адрес, указанный в ListenUri), но в WSDL будет установлен правильный Uri (указанный в адресе).
Самое досадное то, что - когда я попробовал это вскоре после того, как опубликовал вопрос, я не смог заставить его работать в IIS, только при самостоятельном размещении в консольном приложении; проверяя себя сегодня, я обнаружил, что это действительно работает; так что теперь я не уверен, почему это не сработало для меня раньше;
В то же время мы сделали простое пользовательское поведение, которое изменило описание сервиса, и в результате конфигурирование адреса, требуемого в WSDL, было изменено; Очевидно, что если есть встроенная поддержка, это намного лучше, так что я надеюсь, у меня будет время на следующей неделе, чтобы разобраться в этом подробнее.
Если вы добавляете SSL поверх существующего сервиса, это, вероятно, также повлияет на режим безопасности привязки для клиента WCF, который вы можете легко переопределить.
Для WSDL, почему бы вам не просто загрузить файлы, изменить URL-адрес на любой другой и опубликовать их вручную в виде файлов?