Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

WCF self hosted service over HTTPS

4.71/5 (10 votes)
27 Nov 2010CPOL2 min read 95.6K   5.2K  
A guide for creating a self hosted WCF SOAP Service over HTTPS.

Introduction

With this article, C# programmers get a very easy way of creating a self hosted WCF Service, discover different WCF bindings, and most importantly, see a step by step guide for installing a server certificate and run their WCF Service over HTTPS.

The code

First of all, we will handle the process of creating the Windows Service that will host the WCF Web Service and set-up the configuration needed for WCF. Create a Windows Service project in Visual Studio, and then add an Installer class using Add Item. Add the method GetServiceProcessInstaller where you can specify the account under which the Windows Service will be installed. Then, add the method GetServiceInstaller where you need to specify a Name and a Description of the Windows Service.

C#
private static ServiceProcessInstaller GetServiceProcessInstaller()
{
    ServiceProcessInstaller installer = 
      new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem };
    return installer;
}

private static ServiceInstaller GetServiceInstaller()
{
    Process pc = Process.GetCurrentProcess();
    Directory.SetCurrentDirectory
    (pc.MainModule.FileName.Substring(0, 
     pc.MainModule.FileName.LastIndexOf(@"\", 
     StringComparison.CurrentCulture)
    ));

    ServiceInstaller installer = new ServiceInstaller
    {
        ServiceName = "WCF Over Https",
        Description = "WCF Over Https"
    };

    return installer;
}

Place these two lines of code in the Installer class constructor:

C#
Installers.Add(GetServiceInstaller());
Installers.Add(GetServiceProcessInstaller());

Now let's create the interfaces that we need in our WCF Service. This WCF Service will host two different bindings, a SOAP one and an HTTP one that will be used for downloading files.

C#
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace WCFOverHttps.WCFHost
{
    [ServiceContract(Namespace = "WCFOverHttps.WCFHost")]
    public interface IWcfHttpService
    {
        [OperationContract]
        [WebGet(UriTemplate = "GetFile/{path}")]
        Stream GetFile(string path);
    }
}

using System.ServiceModel;

namespace WCFOverHttps.WCFHost
{
    [ServiceContract(Namespace = "WCFOverHttps.WCFHost")]
    public interface IWcfSoapService
    {
        [OperationContract]
        string HelloWorld();
    }
}

Once we finish creating the interfaces and specifying all the methods we will add to our WCF Service, it's time to write the actual implementation of the Service.

C#
using System;
using System.IO;
using System.ServiceModel.Web;

namespace WCFOverHttps.WCFHost
{
    public class WcfService : IWcfHttpService, IWcfSoapService
    {
        public string HelloWorld()
        {
            return "Hello World";
        }

        public Stream GetFile(string path)
        {
            path = string.Format("c:\\{0}", path);
            try
            {
                if (!File.Exists(path))
                    throw new Exception("File not found");

                if (WebOperationContext.Current != null)
                    WebOperationContext.Current.OutgoingResponse.ContentType = 
                       "application/octet-stream";

                return File.OpenRead(path);
            }
            catch (Exception ex)
            {
                if (WebOperationContext.Current != null)
                    WebOperationContext.Current.OutgoingResponse.
                         SetStatusAsNotFound(ex.Message);

                return null;
            }
        }
    }
}

The final step in finishing the WCF Service is the ServiceModel configuration, so just add an Application Configuration File using Add Item, and under configuration section, we will add the system.ServiceModel section where we will configure all endpoints and security settings.

XML
<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <bindings>
      <basicHttpBinding>
        <binding name ="soapBinding">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </basicHttpBinding>
      <webHttpBinding>
        <binding name="httpBinding">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name="WCFOverHttps.WCFHost.WcfService"
               behaviorConfiguration="ServiceBehaviour">
        <host>
          <baseAddresses>
            <add baseAddress="https://192.168.0.2:81/WcfService"/>
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding="basicHttpBinding"
                  bindingConfiguration="soapBinding"
                  contract="WCFOverHttps.WCFHost.IWcfSoapService" />
        <endpoint address="https://192.168.0.2:81/WcfService/http"
                  binding="webHttpBinding"
                  bindingConfiguration="httpBinding"
                  contract="WCFOverHttps.WCFHost.IWcfHttpService"
                  behaviorConfiguration="WebBehavior"/>
        <endpoint address="mex"
                binding="mexHttpsBinding"
                contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="WebBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <serviceDebug includeExceptionDetailInFaults="False"/>
          <serviceMetadata httpsGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
</system.serviceModel>

You can customize in this config section the URL of the WCF Service and also the URL of each endpoint separately. The HTTPS configuration is found in the binding configuration: <security mode="Transport">.

Now the Window Service is finished, and we can install it using the command InstallUtil32(64).exe WCFOverHttps.exe, but if you test it now, it won't work because there is no certificate installed and authorized for the WCF Server. So let's install a certification authority and then use it to create and sign a server certificate:

  1. Open the Visual Studio Command Prompt.
  2. Create the certificate authority:
  3. makecert.exe -sv SignRoot.pvk -cy authority -r 
      signroot.cer -a sha1 -n "CN=AuthorityName" 
      -ss my -sr localmachine
  4. Create the server certificate:
  5. makecert.exe -iv SignRoot.pvk -ic signroot.cer -cy 
      end -pe -n CN="localhost" -eku 1.3.6.1.5.5.7.3.1 -ss 
      my -sr localmachine -sky exchange 
      -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12

The certificate is now installed, but we need to map it to the port specified in the WCF Service configuration file (here, we have port 81). We can do this by using the attached HttpConfig utility. Open it and go to the SSL tab, click Add, enter the IP address of your WCF Service, the port, the GUID of the Windows Service found in AssemblyInfo, and then Browse for the certificate you just created. Click OK and then Apply, and your WCF Service should work now over secure HTTPS.

Future goal

Find a way of self hosting an HTTPS WCF Service with an embedded certificate so it can be easily moved to any server. Any suggestions really appreciated.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)