Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I combine the WCF services config for both http and https in one web.config?

I spent a lot of time figuring out how to configure my WCF services so that they would work for https in the production environment.

Basically, I needed to do this:

<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> 

Adding the bindingNamespace attribute to the endpoint is the final thing that made it work.

But this config doesn't work in my local dev environment where I'm working under regular http. So my config there is:

<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> 

The differences here are that I've set the httpsGetEnabled attribute to false, and I removed the bindingConfiguration and bindingNamespace.

The problem is: how do I create one config block that handles BOTH?

I really hate having to make lots of special modifications to the config every time I do a release. Yes, I know I could have a post-build task that automatically changes the values, but I'd like to merge the configs if possible.

I tried something like this:

<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> 

I figured that putting both endpoints would give it two options to look for when activating the service. However, this doesn't work. I get this error:

Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http].

From looking around SO and the rest of the internet, it appears that others have had problems slaying this dragon.

like image 391
sohtimsso1970 Avatar asked Dec 03 '10 15:12

sohtimsso1970


People also ask

How to configure WCF service in Web config?

Starting with . NET Framework 4, WCF comes with a new default configuration model that simplifies WCF configuration requirements. If you do not provide any WCF configuration for a particular service, the runtime automatically configures your service with default endpoints, bindings, and behaviors.

How do I enable https access for WCF RESTful service?

Add a new WebHttpBinding configuration that has security mode set to Transport . Assign that new WebHttpBinding configuration to the your Service Endpoint binding. Make sure that your RESTful service can only be accessed via HTTPS by setting httpGetEnabled="false" . Set up the metadata publishing endpoint to use HTTPS.

When configuring a WCF service using visual studio?

When configuring a service in Visual Studio, use either a Web. config file or an App. config file to specify the settings. The choice of the configuration file name is determined by the hosting environment you choose for the service.

What is configuration Svcinfo?

configuration.svcinfo: Contains a snapshot of the configuration generated for the client service endpoint for the local (app|web).config. configuration91. svcinfo: For each property in config, contains an XPath to the setting and the original value stored in config.


2 Answers

Well, one problem with your combined config is that your two endpoints are on the same address - that won't work.

If you're hosting in IIS, then your server, virtual directory and the *.svc file needed will determine your basic address - it'll be something like:

http://yourservername/VirtualDirectory/YourService.svc 

If you want to have two endpoints, at least one of them needs to define a relative address:

<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> 

In this case, you'd have your HTTP endpoint on:

http://yourservername/VirtualDirectory/YourService.svc/basic 

and your secure HTTPS endpoint on:

https://yourservername/VirtualDirectory/YourService.svc/secure 

Furthermore: your secure endpoint uses a HttpsBinding configuration - but you're lacking such a binding configuration - all you have is:

<bindings>   <basicHttpBinding>     <binding name="HttpBinding">       <security mode="None">         <transport clientCredentialType="None"></transport>       </security>     </binding>   </basicHttpBinding> </bindings> 

You need to add the HttpsBinding configuration!!

<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> 
like image 57
marc_s Avatar answered Sep 19 '22 12:09

marc_s


I recently had to make a WCF 3.5 REST (webHttpBinding) service available on both HTTP and HTTPS in a Microsoft Azure App Service (IIS). It was a fun... and agonizing adventure. Here are my findings and my web.config's <system.serviceModel>:

Note: these notes are for a WCF REST web-service running using *.svc (@ServiceHost) files within a minimal ASP.NET 4.7 application (with Global.asax) within IIS 10 on Windows Server 2016. These notes do not apply to self-hosted WCF services, non-REST WCF services (i.e. SOAP), or platforms older than .NET Framework 4.7. This also does not apply to .NET Core.

  • Upgrade to .NET Framework 4.7.2 or later (that's just common-sense)
  • The most important part is using the <serviceHostingEnvironment> element is essential, ensure that multipleSiteBindingsEnabled="true" is set.
    • This is documented here:
      • https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/supporting-multiple-iis-site-bindings
      • https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/servicehostingenvironment
    • It looks like this was added in .NET Framework 4.0 ( https://blogs.msdn.microsoft.com/saurabs/2012/11/21/wcf-handling-multiple-iis-bindings/ ), in .NET 3.5 you needed to use <baseAddressPrefixFilters> which are not necessary anymore.
  • You do not need the <serviceMetadata> element in your web.config file at all.
    • Apparently this element is for WSDL metadata - and RESTful services do not support WSDL.
    • I point this out because there's at least a few top Google search results for articles and StackOverflow postings where people say this is required. Those people are incorrect.
  • Do not use absolute URIs in your <endpoint address="" attributes - just leave the attribute empty.
    • This was only necessary in WCF 3.5.
    • Microsoft says to leave it blank (or use a relative URI for PATH_INFO-style endpoints) when hosting WCF in IIS:
      • Read this article: https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/deploying-an-internet-information-services-hosted-wcf-service

        You must always use relative endpoint addresses for IIS-hosted service endpoints. Supplying a fully-qualified endpoint address (for example, http://localhost/MyService.svc) can lead to errors in the deployment of the service if the endpoint address does not point to the IIS-application that hosts the service exposing the endpoint. Using relative endpoint addresses for hosted services avoids these potential conflicts.

  • WCF will detect if it can be reached using both HTTP and HTTPS and will raise an error if the web.config file tells WCF to accept HTTPS connections when the hosting application (i.e. IIS) does not have HTTPS enabled in its parent website.
    • This was unexpected to me because all other web-application platforms I've used don't complain if they're configured for HTTPS but the parent webserver isn't.
      • Especially given that in this case, WCF runs with/inside the .NET request pipeline and ASP.NET certainly doesn't care about IIS' Website Binding (because ASP.NET is designed to be agnostic about parent Website bindings)
      • Note: "website bindings" refers to IIS Website Bindings, not "WCF bindings" which are a separate concept.
  • To get this working locally in Visual Studio and IIS Express, ensure that the parent Web Application Project has "SSL Enabled = True" in the "Properties" window (not the same thing as the "Project Properties" window (yes, I screamed too):
    • enter image description here
  • In .NET 4.6.1, Microsoft simplified WCF's configuration by allowing the <services> element to be omitted and be automatically generated behind-the-scenes, however I didn't have consistent results with RESTful services with dual-HTTP+HTTPS bindings, so I still specify my <services> manually.
    • This is documented here: https://docs.microsoft.com/en-us/dotnet/framework/wcf/simplified-configuration

TL;DR:

Here's my <system.serviceModel> element from my web.config file:

<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> 
like image 22
Dai Avatar answered Sep 16 '22 12:09

Dai