Hosting WCF service as a Windows Service

by MSwaffer 3. November 2008 15:39

One of the cool things aboutWCF is that it doesn't need to be hosted in IIS.  Of course, hosting in IIS is the easy way to do things but there are times when you want to run a service but you don't want to expose it to the world.  Today I worked through some of the issues around hosting a WCF in a managed Windows Service so I am going to put down some notes about the experience. 

First, my goal.  I wanted to expose a service that will be consumed by two different web sites but I don't want the service exposed to the world.  My service will be exposed over TCP/IP or the Net.Tcp binding.  

My first step was to create a WCF Class Library which actually contains my WCF service contract.  There is no App.config associated with this project since it is just a .dll and any App.config you include will just be ignored.  All this library needs is your Data and Service contracts along with the actual service code that implements these.  

The next step was to create a Windows Service that will host this WCF service.   Main from this service looks pretty simple:

static class Program {
    static void Main() {
      ServiceBase[] ServicesToRun;
      ServicesToRun = new ServiceBase[] { new Service1() };
      ServiceBase.Run(ServicesToRun);
    }
  }

Just creates an array of services, adds a new Service1 (which is my Windows Service class, not the WCF class) and then runs the services.

My Service1 class is my actual Windows Service, again, not my WCF service.  I think I could have used an App.config here but I decided to hard code the end points for my WCF into this service.  My thinking is that if this ever changes I am probably going to recompile or remove this service anyway.  I still won't have to touch my WCF Class Library though to host it somewhere else.

public partial class Service1 : ServiceBase {
    public Service1() {
      InitializeComponent();
    }

    private ServiceHost serviceHost;

    protected override void OnStart(string[] args) {
      serviceHost = new ServiceHost(typeof(MyWcfService));

      Binding binding = new NetTcpBinding();
      string address = "net.tcp://localhost:9000";
      Binding mexBinding = MetadataExchangeBindings.CreateMexHttpBinding();
      string mexAddress = "http://localhost:8000/MEX";

      ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
      mexBehavior.HttpGetEnabled = true;
      mexBehavior.HttpGetUrl = new Uri(mexAddress);
      serviceHost.Description.Behaviors.Add(mexBehavior);

      serviceHost.AddServiceEndpoint(typeof(IMyWcfService), binding, address);
      serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexAddress);

      serviceHost.Open();
    }

    protected override void OnStop() {
      serviceHost.Close();
    }
  }

First I create my serviceHost... this is the guy who is actually hosting my WCF service.  Then I create my bindings.  I created two... the net.tcp one is the on that I am going to be listening on for client requests.  The mexBinding one is to expose my WSDL definition.  I decided to just do that on HTTP localhost to make things easy... then of course quickly discovered a problem with doing this in Vista. 

It turns out that Vista has extra security for allowing anyone to communicate over HTTP that isn't IIS.  I kept getting an "AddressAccessDeniedException" which (eventually) I found out was caused by lack of permissions.  The symptom was that my service would start... and then just stop itself.  Fortunately there were plenty of messages in my EventViewer to help me track down the problem.  Below is a link to the article I used to figure out how to set my ACLs properly.  Basically it boils down to running this in the command line:

netsh http add urlacl url=http://+:8000/ user=everyone

Yes... I know... I really shouldn't add "everyone" but you get the idea.  You could just supply the normal user name there instead of everyone.  Incidentally the + sign is a wildcard to indicate that all URLs at that port will be allowed.

Back to the code though.  After I added my bindings I needed to add my Mex behavior.  I missed this piece on the first go-round so don't forget this step! 

The last thing in this code is to add your service endpoints to your service and then open the service.  Notice that the OnStop() method is where you close the service.  These are the methods that are called when you start / stop a service in the MMC. 

Finally, I added an installer so that my Windows Service could be installed.

I did this the quick-n-dirty way but it worked.  In the Design View of the Service1 class, right click and choose "Add Installer".

This gave me a ProjectInstaller class in Design View that had serviceInstaller1 and serviceProcessInstaller1. 

Here you can open the Properties pane of the serviceInstaller1 and change the Display and ServiceName properties.  You also will probably want to change one property on serviceProcessInstaller1, the Account property.  I ran mine as the NetworkService account.

Once you have all of this in place, you just build and you are ready to use InstallUtil to install your Windows Service that is hosting your WCF service.

Following are some links that I used to help me figure this thing out. 

Links:

 

Tags:

c# | WCF

Comments are closed

About the author

I wrote my first program on a Vic 20 that my brother and I bought when I was 11.  It fascinated me that I could type in some instructions and the computer would do what I told it to do!  It fascinated my brother that you could plug things into the back of the computer.  I went on to become a computer programmer, he went on to be an electrician!

I spent the 90's working for FedEx driving a delivery truck until sometime in 2000 my senior manager sat me down and said "What are you doing here?  You need to go to school and do computer stuff!"  So I went to school, which FedEx graciously paid for.

Right out of school in late 2004 I started a business from my home doing independent software development and database work.  I worked with a lot of very cool people on some very cool projects all across the nation, mostly for people I never met!  During this time I mostly developed web apps in PHP working with MySQL databases although I dabbled with some Perl and some PostgreSQL in there as well.  

In 2006 I got a job working for SharperAgent in Denver, CO. as a web developer.  We did a lot of XSLT and JavaScript as well as the usual HTML / CSS work.  I learned a lot from the guys down there. 

About 6 months later I got a job offer from a company about 5 miles away from my house.  At that point I was commuting 50 miles to SharperAgent and the new company, Eclipse Software Systems, Inc., wanted me as a software developer, not just doing web development.  I jumped at the chance and haven't looked back.  

At Eclipse we do software for the trucking industry, which isn't nearly as boring as it might sound!  We do C# and Delphi and work mainly with Sql Server and Sql Server CE databases.  We use a number of Agile software development methodologies, sort of a mixture between Lean, XP, Kanban and a little bit of Scrum.  We get to experiment with the processes a lot which is cool and even more cool, we stay up to date on the latest technologies.  

Anyway, that is what I do. I love my job and I truly enjoy programming.  I started this web site mainly as a little place to write up some things that I learned as I went along.  I find myself every day using Google to find other people's article on how they solved a problem so this is kind of my way of giving back. 

FWIW, I don't consider this a "blog"... this is just a place for me to take notes.  :)