Automatic WCF web service binding via http or https

by zebsadiq 19. May 2011 10:13

I recently needed a way to be able to deploy a web service project to different environments, where each environment was either using http or https to offer the web service to the multiple clients. If you find yourself in the same situation, then this technique might save you a bit of time.

Before we begin, you should note that this technique requires both protocols to be active on the IIS site where the web service is being accessed. I did not investigate the alternate to this scenario, you may or may not be willing to do so.

When I google-ed to find examples on this topic, I was surprised by a) The amount of different options available when configuring a WCF web service b) People confusing others by suggesting ‘one configuration fits all’ solutions rather than understanding the requirements first. c) The lack of documentation and clear examples regarding WCF web services and their different flavours of setup.  Every set of requirements are different, the following solution met all of my requirements.

Let me begin by clarifying, that in a WCF web service configurations, you do not need to define the exact end point url to your web service, in the web.config file of your hosting site. This is a bit of a myth, maybe since most WCF examples I did came across seemed to suggest that this url was necessary. The url to the web service only needs to be defined in the client web or app.config. I discovered this after much google’ing when I came across the <protocolMapping> tag. This tag can be defined inside the <system.serviceModel> tag in the web.config.  Here is a sample of how protocolMapping can be configured.

<system.serviceModel>
    <services>
      <service behaviorConfiguration="MyProjectWCFServiceBehaviour" name="MyCompany.MyProject.MyProjectWCFService"></service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyProjectWCFServiceBehaviour">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <dataContractSerializer maxItemsInObjectGraph="2147483646" />
          <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <protocolMapping>
      <add scheme="http" binding="basicHttpBinding" bindingConfiguration="MyHttpBinding" />
      <add scheme="https" binding="basicHttpBinding" bindingConfiguration="MyHttpsBinding" />
    </protocolMapping>
    <bindings>
      <basicHttpBinding>
        <binding name="MyHttpBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="500000000" maxBufferPoolSize="524288" maxReceivedMessageSize="500000000" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="2147483646" maxBytesPerRead="4096" maxNameTableCharCount="5242880" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
        <binding name="MyHttpsBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="500000000" maxBufferPoolSize="524288" maxReceivedMessageSize="500000000" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="2147483646" maxBytesPerRead="4096" maxNameTableCharCount="5242880" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
  </system.serviceModel>

Notice how there is no url defined for the web service in the above configuration. The two ‘add’ tags in the <protocolMapping> tags, define what protocols are to be mapped to which basicHttpBinding. Since http and https bindings have to be configured differently (unfortunately), there are two different bindings defined inside the <basicHttpBinding> tags.  In the client config file (bellow) definition, these two bindings are defined in the exact same way as the server config file. Of course an endpoint needs to be defined in the client .config file. Depending on whether the web service is accessed over http or https, the endpoint’s bindingConfiguration property could be set to a binding definition compatible with that protocol.

<system.serviceModel> 
        <bindings> 
            <basicHttpBinding> 
                <binding name="BasicHttpBinding_IMyProjectWCFService" closeTimeout="00:01:00" 
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
                    maxBufferSize="500000000" maxBufferPoolSize="524288" maxReceivedMessageSize="500000000" 
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
                    useDefaultWebProxy="true"> 
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
                    <security mode="TransportCredentialOnly"> 
                        <transport clientCredentialType="Windows" realm="" /> 
                    </security> 
                </binding> 
                <binding name="BasicHttpsBinding_IMyProjectWCFService" closeTimeout="00:01:00" 
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
                    maxBufferSize="500000000" maxBufferPoolSize="524288" maxReceivedMessageSize="500000000" 
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
                    useDefaultWebProxy="true"> 
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
                    <security mode="Transport"> 
                        <transport clientCredentialType="Windows" realm="" /> 
                    </security> 
                </binding> 
            </basicHttpBinding> 
        </bindings> 
        <client> 
            <endpoint address="http://www.myproject.com/MyProjectQCWCFService.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyProjectWCFService" 
                contract="MyProjectWCFService.IMyProjectWCFService" name="BasicHttpBinding_IMyProjectWCFService" /> 
        </client> 
    </system.serviceModel>

I found this solution to be extremely flexible considering that I didn’t have to define and maintain fixed url’s for each different environment where deployed my solution. I hope this works for you.

Tags: , , ,

C# | WCF | .net 4 | Asp.net

Comments

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Calendar

<<  January 2020  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar