How to host a WCF service that uses Castle Windsor in a Windows Service

Setup

Currently I’m working on a web application project that also uses a WCF service for some operations. We are a big fan of using ALT.NET and are using Castle Windsor to do IoC (Inversion of Control)/Dependency Injection. The problem we were having was the small delay to start up the worker process in IIS. Which is not much you can do about within IIS. (As far as I know) Except for maybe making a wake up service that calls a simple method every x minutes. Just to keep the worker process alive.

If you don’t want to wake up the IIS worker process you can always host your WCF service in a managed application, a windows service for instance. This is something that is always running (if it automatically starts and is not stopped manually of course).

Castle Windsor

I’m not going to go into the details on why you should use Castle Windsor. Maybe another post. The main goal of this post is to get the WCF service that uses Castle Windsor hosted within the Windows Service. You’re maybe wondering..is this then so complex? Well it can give some problems. You will find many posts on the Internet concerning this matter. However many of these posts focus on hosting the WCF Service in IIS.

What I’m not going to discuss

Like I’m not going to go into the details of Windsor, I’m also not going to say how you create a WCF service or how you create a Windows Service. MSDN Library is a very handy resource for this.

Make Windsor work

To make Castle Windsor work you’ll need to do several things:

  • Reference the necessary libraries
  • Create a windsor.config or windsor.boo file (or both)
  • Create a windsor container
    • Add a facility
    • Load the config file
    • Register the container

One thing I’m going to say is that the Castle project has done a lot of effort into making it all work out. To make WCF and Windsor play nice together you have to use Castle.Facilities.WcfIntegration. This contains a factory for hosting the service, namely the ServiceHostFactory.

The difference between IIS and a managed application

The difference isn’t really all that big..you just have to do the proper config and make sure you do all the aforementioned prep work like you would do it when hosting the service via IIS.

When you would host the WCF service in IIS, you would do all the prep work in the global.asax. You don’t have this in a Windows Service or a console application. So just do this somewhere else. I’m not saying hosting the WCF service in IIS is bad..it has it’s advantages.

Let’s put this into practice

1) Reference the necessary libraries:

   1: using System;
   2: using Castle.Facilities.WcfIntegration;
   3: using Castle.Windsor;
   4: using Castle.Windsor.Installer;
   5: using Rhino.Commons;

2) Create a windsor.config or windsor.boo file (or both)

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <components>
   4:     <component id="MyWCFService"
   5:                    service="WCFServices.IMyWCFService, WCFServices"
   6:            type="WCFServices.MyWCFService, WCFServices">
   7:     </component>
   8:   </components>
   9: </configuration>

3) Create and register the WindsorContainer (IWindsorContainer). Normally you would do this in the global.asax. Now you need to define a method where you will do this part.

Now I’ll create a method that will create and register the necessary container. This method looks like this:

Declare a public WindsorContainer:

   1: IWindsorContainer Container { get; private set; }

Create the method, PrepWindsor (This will be called in our main method):

   1: Container = new WindsorContainer()
   2:       .AddFacility<WcfFacility>()
   3:       .Install(Configuration.FromXmlFile("Windsor.config"));
   4:  
   5: DefaultServiceHostFactory.RegisterContainer(Container.Kernel);

Now we have done all of the prepwork for Windsor. Now let’s create the ServiceHost. We will use the following class for this: Castle.Facilities.WcfIntegration.DefaultServiceHostFactory

   1: PrepWindsor();
   2:             
   3: using(var host = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory().CreateServiceHost(typeof(WCFServices.IMyWCFService).AssemblyQualifiedName,new Uri[0]))
   4: {
   5:      host.Open();
   6: }

As you can see I don’t create any endpoints programmatically. This happens via a config file that I have added. My App.config looks like this:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <system.serviceModel>
   4:     <behaviors>
   5:       <serviceBehaviors>
   6:         <behavior name="WCFServices.WCFServiceBehavior">
   7:           <serviceMetadata httpGetEnabled="true" />
   8:           <serviceDebug includeExceptionDetailInFaults="true" />
   9:         </behavior>
  10:       </serviceBehaviors>
  11:     </behaviors>
  12:     <services>
  13:           <service behaviorConfiguration="WCFServices.WCFServiceBehavior"
  14:         name="WCFServices.MyWCFService">
  15:         <endpoint address="WCFServices" binding="basicHttpBinding" contract="WCFServices.IMyWCFService">
  16:           <identity>
  17:             <dns value="localhost" />
  18:           </identity>
  19:         </endpoint>
  20:         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  21:         <host>
  22:           <baseAddresses>
  23:             <add baseAddress="http://localhost:8000/" />
  24:           </baseAddresses>
  25:         </host>
  26:       </service>
  27:     </services>
  28:   </system.serviceModel>
  29: </configuration>

Ok that should be it! Now you should be able to properly host the service in the managed application.

I would love to hear some feedback or if you have questions/remarks, please let me know.

kick it on DotNetKicks.com Shout it Progg it vote it on WebDevVote.com