Categories
Uncategorized

WCF and Sharing Ports

WCF can become a tricky beast to configure once you start hosting multiple services on the same port not to mention hosting it inside a Windows service. I ran into a few challenges in getting things up and running. Hopefully this short article might save someone a lot of time and effort if you find yourself in a similar situation.

Sharing ports among WCF services can become an issue when dealing with production environments. Many examples that you find use a different port for each WCF service that is created. This approach works fine for prototyping and in academia. However your IT guy will probably break into a diatribe about security and maintainability when you want to deploy the service. This is especially true if you are deploying to a client’s network. So let’s save the IT guy unnecessary stress and share a port. I encountered a couple of issues while tackling this problem.

The first obstacle was hosting multiple services inside a Windows service. I really prefer hosting WCF in IIS, but that is another discussion. Suffice it to say that the due to design choices beyond my control and prior to my tenure on the project, WCF services were hosted in a Windows service. I created a simple Windows service to act as a host. Here is the code called by the Service Control Manager when the Windows Service is started and stopped.

    public partial class WcfServiceHost : ServiceBase
    {
        private readonly List<ServiceHost> _myServiceHosts = new List<ServiceHost>();

        public WcfServiceHost()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            OpenServiceHost<HelloService>();
            OpenServiceHost<GoodbyeService>();
        }

        protected override void OnStop()
        {
            CloseServiceHosts();
        }

        private void OpenServiceHost<T>()
        {
            var serviceHost = new ServiceHost(typeof(T));
            serviceHost.Open();
            _myServiceHosts.Add(serviceHost);
        }

        private void CloseServiceHosts()
        {
            foreach (var serviceHost in _myServiceHosts)
            {
                if (serviceHost.State == CommunicationState.Opened)
                {
                    serviceHost.Close();
                }
            }
        }
    }

The code is pretty straightforward. The OnStart(string[] args) and OnStop() methods for the Windows service give us the opportunity to open and close the WCF services. I threw in a generic method to spin up the ServiceHost instances for various types. Next let’s tackle to configuration.

The second problem that I encountered was getting the configuration correct. A lot of example out there for hosting multiple services in a single Windows service were all code based. This is not helpful when your WCF is setup via configuration. For this example I created the server configuration manually. No wizards or designers were used. Here is the configuration for the server.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <system.serviceModel>
    <services>
      <service name="WcfWindowsServiceHostExample.HelloService" behaviorConfiguration="exampleBehavior">
        <endpoint address="http://localhost:8888/HelloService" binding="basicHttpBinding" contract="WcfWindowsServiceHostExample.IHelloService">
          <!--identity>
            <dns value="localhost" />
          </identity-->
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8888/HelloService" />
          </baseAddresses>
        </host>
      </service>
      <service name="WcfWindowsServiceHostExample.GoodbyeService" behaviorConfiguration="exampleBehavior">
        <endpoint address="http://localhost:8888/GoodbyeService" binding="basicHttpBinding" contract="WcfWindowsServiceHostExample.IGoodbyeService">
          <!--identity>
            <dns value="localhost" />
          </identity-->
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8888/GoodbyeService" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="exampleBehavior">
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Here are a few pitfalls to avoid. Make sure your base address is defined for the mex endpoint. Remember to include the serviceMetadata element with the httpGetEnabled attribute set to true. These items are required in order for the service to be discoverable by your client application. To Test the WCF services out, I created a simple console application and added a service reference to generate the proxies. You can download the entire project here.

Leave a Reply

Your email address will not be published. Required fields are marked *