Как я могу объединить конфигурацию служб WCF для http и https в одном web.config?
Я потратил много времени на то, как настроить мои службы WCF, чтобы они работали на https в рабочей среде.
В принципе, мне нужно было сделать это:
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<services>
<service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint address="" bindingNamespace="https://secure.mydomain.com" binding="basicHttpBinding" bindingConfiguration="HttpsBinding" contract="MyNamespace.IMyService"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="HttpsBinding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
Добавление атрибута bindingNamespace
к конечной точке - последнее, что заставило его работать.
Но эта конфигурация не работает в моей локальной среде, где я работаю под обычным http. Итак, моя конфигурация:
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<services>
<service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="MyNamespace.IMyService"/>
</service>
</services>
Различия здесь в том, что я установил атрибут httpsGetEnabled
в значение false, и я удалил bindingConfiguration и bindingNamespace.
Проблема заключается в следующем: как создать один блок конфигурации, который обрабатывает BOTH?
Мне очень жаль, что каждый раз, когда я делаю релиз, приходится делать много специальных изменений в конфиге. Да, я знаю, что у меня может быть задача пост-сборки, которая автоматически изменяет значения, но я хотел бы объединить конфигурации, если это возможно.
Я пробовал что-то вроде этого:
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<services>
<service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="MyNamespace.IMyService"/>
<endpoint address="" bindingNamespace="https://secure.mydomain.com" binding="basicHttpBinding" bindingConfiguration="HttpsBinding" contract="MyNamespace.IMyService"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="HttpsBinding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
Я полагал, что включение обеих конечных точек даст ему два варианта поиска при активации службы. Однако это не работает. Я получаю эту ошибку:
Не удалось найти базовый адрес, соответствующий схеме https для конечной точки со связыванием BasicHttpBinding. Схемы зарегистрированных базовых адресов: [http].
От взгляда вокруг SO и остальной части Интернета, похоже, что у других были проблемы с убийством этого дракона.
Ответы
Ответ 1
Ну, одна проблема с вашей комбинированной конфигурацией заключается в том, что ваши две конечные точки находятся на одном адресе - это не сработает.
Если вы размещаете в IIS, то ваш сервер, виртуальный каталог и необходимый файл *.svc будут определять ваш основной адрес - это будет что-то вроде:
http://yourservername/VirtualDirectory/YourService.svc
Если вы хотите иметь две конечные точки, по крайней мере один из них должен определить относительный адрес:
<services>
<service name="MyNamespace.MyService"
behaviorConfiguration="MyServiceBehavior">
<endpoint
address="basic"
binding="basicHttpBinding"
contract="MyNamespace.IMyService"/>
<endpoint
address="secure"
binding="basicHttpBinding" bindingConfiguration="HttpsBinding"
contract="MyNamespace.IMyService"/>
</service>
</services>
В этом случае у вас будет конечная точка HTTP:
http://yourservername/VirtualDirectory/YourService.svc/basic
и ваша защищенная конечная точка HTTPS:
https://yourservername/VirtualDirectory/YourService.svc/secure
Кроме того: ваша защищенная конечная точка использует конфигурацию HttpsBinding
- но вам не хватает такой конфигурации привязки - все, что у вас есть:
<bindings>
<basicHttpBinding>
<binding name="HttpBinding">
<security mode="None">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
Вам нужно добавить конфигурацию HttpsBinding
!
<bindings>
<basicHttpBinding>
<binding name="HttpBinding">
<security mode="None">
<transport clientCredentialType="None"></transport>
</security>
</binding>
<binding name="HttpsBinding">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
Ответ 2
Проблема связана не с конфигурационным файлом, а с настройкой IIS.
Вам необходимо включить HTTP и HTTPS в IIS.
В IIS 7.5 перейдите на свой сайт и нажмите "Привязки" в разделе "Изменить действие сайта". Убедитесь, что добавлены как http, так и https.
Затем вам нужно создать привязку для HTTP под <basicHttpBinding>
, при этом режим безопасности не будет установлен.
Добавьте вновь созданную конфигурацию привязки к конечной точке http.
Тебе хорошо идти. Дайте мне знать, если вам нужна дальнейшая проблема.
Ответ 3
Решением для запуска в локальном домене, а также для работы в производственной и других средах, не полагаясь на память, чтобы что-либо изменить, является преобразование конфигурации. Они преобразуют скомпилированный файл web.config на основе выбранного профиля конфигурации. Локально я работаю в режиме Debug
, в среде тестирования я публикую в профиль TestRelease
, и у меня есть другой профиль:
![Web.Config Transforms in Visual Studio]()
Если вы не можете расширить свой файл web.config, вы можете щелкнуть правой кнопкой мыши и добавить конфигурационные преобразования. Чтобы получить больше, чем Debug и Release, вы добавляете больше конфигураций через менеджер:
![Configuration Manager in Visual Studio]()
Вот пример преобразования:
Web.Debug.config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--...-->
<system.serviceModel>
<protocolMapping>
<add binding="basicHttpBinding" scheme="http" xdt:Transform="SetAttributes" />
</protocolMapping>
<bindings>
<basicHttpBinding>
<binding xdt:Locator="Match(name)" name="basicHttpBindingConfiguration">
<security xdt:Transform="Remove">
<transport xdt:Transform="Remove"/>
</security>
</binding>
<binding xdt:Locator="Match(name)" name="fileTransferBinding">
<security xdt:Transform="Remove">
<transport xdt:Transform="Remove"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
Web.Release.config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--...-->
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" xdt:Transform="Replace"/>
<serviceDebug includeExceptionDetailInFaults="false" xdt:Transform="Replace"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" xdt:Transform="Replace"/>
</protocolMapping>
<bindings>
<basicHttpBinding>
<binding xdt:Locator="Match(name)" name="basicHttpBindingConfiguration">
<security mode="Transport" xdt:Transform="Insert">
<transport clientCredentialType="None" proxyCredentialType="None" />
</security>
</binding>
<binding xdt:Locator="Match(name)" name="fileTransferBinding">
<security mode="Transport" xdt:Transform="Insert">
<transport clientCredentialType="None" proxyCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="false" xdt:Transform="Replace"/>
</system.webServer>
</configuration>
Ответ 4
Недавно мне пришлось сделать службу WCF 3.5 REST (webHttpBinding
) доступной как по HTTP, так и по HTTPS в службе приложений Microsoft Azure (IIS). Это было веселое и мучительное приключение. Вот мои выводы и мой web.config
<system.serviceModel>
:
Примечание: эти примечания предназначены для веб-службы WCF REST, работающей с использованием файлов *.svc
(@ServiceHost
) в минимальном приложении ASP.NET 4.7 (с Global.asax
) в IIS 10 на Windows Server 2016. Эти примечания не применяется к автономным службам WCF, службам WCF без REST (например, SOAP) или к платформам, более ранним, чем .NET Framework 4.7. Это также не относится к .NET Core.
- Обновление до .NET Framework 4.7.2 или новее (это просто здравый смысл)
- Самая важная часть - это использование элемента
<serviceHostingEnvironment>
, убедитесь, что установлен multipleSiteBindingsEnabled="true"
.
- Вам вообще не нужен элемент
<serviceMetadata>
в вашем файле web.config
.
- Очевидно, этот элемент предназначен для метаданных WSDL, а службы RESTful не поддерживают WSDL.
- Я указываю на это, потому что есть по крайней мере несколько лучших результатов поиска Google для статей и сообщений Qaru, где люди говорят, что это требуется. Эти люди не правы.
- Не используйте абсолютные URI в ваших атрибутах
<endpoint address=""
- просто оставьте атрибут пустым.
- Это было необходимо только в WCF 3.5.
- Microsoft говорит оставить это поле пустым (или использовать относительный URI для конечных точек
PATH_INFO
-style) при размещении WCF в IIS:
- WCF определит, можно ли достичь этого с использованием как HTTP, так и HTTPS, и выдаст ошибку, если файл
web.config
скажет WCF принять HTTPS-подключения, когда в хост-приложении (т.е. IIS) не включен HTTPS на его родительском веб-сайте.
- Это было неожиданно для меня, потому что все остальные платформы веб-приложений, которые я использовал, не жалуются, если они настроены для HTTPS, а родительский веб-сервер - нет.
- Особенно с учетом того, что в этом случае WCF работает с/внутри конвейера запросов .NET, а ASP.NET, безусловно, не заботится о привязке веб-сайтов IIS (поскольку ASP.NET не зависит от привязок родительских веб-сайтов)
- Примечание. "Привязки веб-сайтов" относятся к привязкам веб-сайтов IIS, , а не - "привязкам WCF", которые представляют собой отдельную концепцию.
- Чтобы это работало локально в Visual Studio и IIS Express, убедитесь, что родительский проект веб-приложения имеет "SSL Enabled = True" в окне "Свойства" (не то же самое, что окно "Свойства проекта" (да, я тоже кричал) ):
- В .NET 4.6.1 Microsoft упростила настройку WCF, позволив элементу
<services>
опускаться и автоматически генерироваться за кадром, однако у меня не было согласованных результатов со службами RESTful с привязками двойного HTTP + HTTPS, поэтому я все еще указываю свой <services>
вручную.
TL; ДР:
Вот мой элемент <system.serviceModel>
из моего файла web.config
:
<system.serviceModel>
<services>
<service name="WcfService1.MainService">
<endpoint address="" binding="webHttpBinding" contract="WcfService1.IMainService" behaviorConfiguration="myWebBehavior" bindingConfiguration="myWebHttpBindingInsecure" />
<endpoint address="" binding="webHttpBinding" contract="WcfService1.IMainService" behaviorConfiguration="myWebBehavior" bindingConfiguration="myWebHttpBindingSecure" />
</service>
<service name="WcfService1.AnotherService">
<endpoint address="" binding="webHttpBinding" contract="WcfService1.IAnotherService" behaviorConfiguration="myWebBehavior" bindingConfiguration="myWebHttpBindingInsecure" />
<endpoint address="" binding="webHttpBinding" contract="WcfService1.IAnotherService" behaviorConfiguration="myWebBehavior" bindingConfiguration="myWebHttpBindingSecure" />
</service>
<!-- etc... -->
</services>
<behaviors>
<endpointBehaviors>
<behavior name="myWebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<!-- By default (in machine.config), the 'http' scheme is mapped to 'basicHttpBinding' (SOAP), not 'webHttpBinding' (REST) and the 'https' scheme is not mapped. -->
<add binding="webHttpBinding" scheme="https" bindingConfiguration="myWebHttpBindingSecure" />
<add binding="webHttpBinding" scheme="http" bindingConfiguration="myWebHttpBindingInsecure" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<webHttpBinding>
<!-- maxReceivedMessageSize="104857600" is 100MiB -->
<binding name="myWebHttpBindingInsecure" maxReceivedMessageSize="104857600" transferMode="Streamed">
<security mode="None" />
</binding>
<binding name="myWebHttpBindingSecure" maxReceivedMessageSize="104857600" transferMode="Streamed">
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>