Creating a .NET WCF enabled Windows Service with authentication in C#.

“I am fluent in over six million forms of communication…” – C-3PO

Historically, all of the services I’ve created on Windows (like a daemon from the Unix world), have been written in C/C++. Recently though however, I’ve needed to create a service in a .NET language like C#. There are several ways of doing this. I could have kept with the C++ model and used CLR integration, but I thought I might give C# a chance this time.

Additionally, not only did I need to create the service, I also needed to enable an IPC (inter process communication) type connection to another .NET application, in this case a web application. I decided to go with WCF (Windows Communications Framework). WCF is very cool, although I suspect not a communication system understood by C-3PO.

Whilst this post describes WCF, it should also be a good description of how to start with Windows Services in .NET.

Creating the service itself was quite easy. I was using Visual Studio 2013 and .NET 4.5. You simply create a new project of the type Windows Service, and you’re half way there.

The first thing to do is to rename Service1.cs in the designer to an appropriate name. This will be the name of your service. If you rename the file in the designer, the designer will rename the class for you as well.

The basic premise of a .NET Windows Service, is that the Service Control Manager on Windows will either automatically on boot, or manually, instruct your service to start. You then add code to be executed on service Start, and code to be executed on service Stop. What you do in between is up to you. Your service might be idle, waiting for an external event to trigger action, or you could have a loop based on a timer to execute tasks on any given frequency.

In this example, we will go with both. This service will react to WCF calls from an external application, and also perform a maintenance task every 24 hours. Additionally, throughout the examples I’ve kept clear of using structured error handling (try/catch/finally), and I’ve hardcoded information in (like the WCF URI). Generally, try make configuration parameters flexible and not hardcoded (perhaps use a .NET settings file, or the registry). Error handling code is also key, but makes the examples somewhat unwieldy.

Let’s add the initial code. All I’m going to do here, is initialize some basic variables and log some entries to the Windows Application Event Log.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Reflection;
using System.ServiceProcess;
using System.Text;

namespace SampleWindowsService
{
	public partial class SampleWindowsService : ServiceBase
	{
		private static string _strAppTitle = "";
		private static string _strAppVersion = "";
		private static string _strAppPath = "";

		public SampleWindowsService()
		{
			Assembly aAssembly = Assembly.GetExecutingAssembly();
			Version vAssembly = aAssembly.GetName().Version;

			InitializeComponent();

			// Initialize Global Variables
			_strAppTitle = "Sample Windows Service";
			_strAppVersion = string.Format("{0}.{1}.{2}", vAssembly.Major, vAssembly.Minor, vAssembly.Build);
			_strAppPath = System.IO.Path.GetDirectoryName(aAssembly.Location);

			// Set Service Parameters
			this.ServiceName = "SampleWindowService";
			this.CanStop = true;
			this.CanPauseAndContinue = false;
			this.AutoLog = true;
		}

		protected override void OnStart(string[] args)
		{
			// Service Startup Code
			this.EventLog.WriteEntry(string.Format("Service {0} (v{1}) starting.", _strAppTitle, _strAppVersion));
		}

		protected override void OnStop()
		{
			// Service Stop Code
			this.EventLog.WriteEntry("Service stopping.");
		}
	}
}

All I’ve done here is import the System.Reflection namespace so that I could determine the assembly’s version, and put some basic initialization and logging code in. The AutoLog parameter instructs the service to automatically create event log entries for the service started and service stopped events. I’ve then added additional log entries for starting and stopping. I’ve also set the CanPauseAndContinue parameter to false. This means my service can be started and stopped, but not paused. If you do enable this, you simply need to override the OnPause and the OnContinue methods. Pausing a service can be useful, for example if you need to have a service still operate internally, but stop listening for client requests.

With that very basic code in place, we now need to install the service so that it can be started and stopped as desired. There are two ways of doing this. One way is to use the .NET InstallUtil utility, the other is to build install functionality into your assembly. In this post I’m going to go with the InstallUtil version, but for those interested here is a link to how to do this programmatically (so the service executable can install and uninstall itself).

The first thing we need to do to enable the service to be installed, is to open the Designer view of the service, right click and select Add Installer. This will add an installer class to your project. You then open the installer class and modify the parameters as required. In particular, you will need to update:

  • The Service Process Installer’s Account parameter – this is where you can configure your service to start as the specified Windows Local/Domain user account, or a system account, e.g. LocalService. Unless you need to use a real user account, stick with LocalService as a default, although be aware that LocalService is a non-administrative account. LocalSystem has full administrative access, but generally try avoid running a service with an administrative account if you can. If this is a real application being developed, ideally use a dedicated windows account with just the specific permissions needed to run the application.
  • The Service Installer’s DisplayName and StartType parameters. The DisplayName parameter sets the name of the service as it appears in the Services administrative tool. The StartType parameter instructs the service to be started automatically on system start, or manually. If you select manually, you will need to use the net start/stop command, or the services administrative tool to start your service.

With that in place, build your project and then use the .NET InstallUtil utility to install the service (installutil nameofyourexecutable.exe). The easiest way to get to this utility is through the Visual Studio Command Prompt.

Now I’m going to add a timer so that we can put in some regular maintenance tasks. In my services, this timer is typically used to kick off a daily log management routine (as I have a tendency towards text file based logs rather than the event log). I’ve included the code excerpts below (I’ve removed the code previously described to keep the code in here readable.

namespace SampleWindowsService
{
	public partial class SampleWindowsService : ServiceBase
	{
		private static System.Timers.Timer _oTimerLoop;
		private const int _iLoopTimer = 24; // Hours

		public SampleWindowsService()
		{
			_oTimerLoop = new System.Timers.Timer();
		}

		protected override void OnStart(string[] args)
		{
			_oTimerLoop.Interval = 5000; // Set Initial Timer Interval to 5 seconds
			_oTimerLoop.Elapsed += _oTimerLoop_Elapsed;
			_oTimerLoop.Start();
		}

		protected override void OnStop()
		{
			_oTimerLoop.Stop();
		}

		private void _oTimerLoop_Elapsed(object sender, EventArgs e)
		{
			// Reset Loop Timer
			_oTimerLoop.Interval = 1000 * 60 * 60 * _iLoopTimer;

			// Initiate Scheduled Tasks...
		}
	}
}

I’ve defined a variable to store an instance of the System.Timers.Timer class, attached an event handler method, and set the initial timeout. I’ve set the timer interval for 5 seconds so that 5 seconds after service start, the scheduled event occurs. In the event handler itself, the timer interval is reset back to 24 hours. So the timer kicks off 5 seconds after start, and then every 24 hours. Yes, I know I’m a bit strange using _oTimerLoop.Interval = 1000 x 60 x 60 x _iLoopTimer instead of simply using _oTimerLoop.Interval = 3600000 x _iLoopTimer. I find it easier to read if I can see the individual numbers, in this case 1000msec * 60 (seconds) * 60 (minutes) * _iLoopTimer (hours).

Now, when your timer routine does execute, it’s generally best to kick off your maintenance task asynchronously. This basically means start another thread, so that thread can execute your maintenance tasks without impacting the controlling thread. You can either use the System.Threading.Thread class, or a System.ComponentModel.BackgroundWorker class for this task.

Well, that’s the basic service structure complete. Let’s move onto WCF.

Windows Communications Framework is a framework for easily enabling communications between processes and systems. The framework handles the bulk of the underlying communications routines so that you can focus on your application logic, and not infrastructure code. In this example, I’m going to add several functions to our service, which can then be called from another application elsewhere.

The first thing we need to do is create an interface to describe the functions we will make available by WCF. An interface is a standard way of externally exposing functionality of a class in an object-oriented programming language. Right click on the project, and add a new interface. I’ve named the interface IIPCService. Interface names typically start with an I. So IPC Service interface gets a name of IIPCService. You will also at this point need to add a project reference to the System.ServiceModel.dll assembly. With that reference added, you can import the System.ServiceModel namespace, and add your list of exposed functions. In the example here, we’re only adding a single function. You can see the ServiceContract and OperationContract attributes added as well. Those attributes can be further configured to adjust the behaviour of WCF.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace SampleWindowsService
{
	[ServiceContract]
	public interface IIPCService
	{
		[OperationContract]
		bool Function1(string strArgument1, out string strResult);
	}
}

With the interface complete, now we need to build the logic itself. A lot of WCF can be controlled through application configuration files, but I’ll be doing the basics programmatically in this example.

Add a class to contain your WCF logic. I created a class called IPCService.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.Text;
using System.Threading.Tasks;

namespace SampleWindowsService
{
	public class IPCService : IIPCService
	{
		private static ServiceHost _sHost = null;

		internal static void StartService()
		{
			BasicHttpBinding httpBinding;

			_sHost = new ServiceHost(typeof(IPCService));
			httpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
			httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

			_sHost.AddServiceEndpoint(typeof(IIPCService), httpBinding, "http://computername:50000/SampleWindowsServiceIPC");

			_sHost.Open();

		}

		internal static void StopService()
		{
			if (_sHost != null)
				_sHost.Close();
		}

		public bool Function1(string strArgument1, out string strResult)
		{
			OperationContext opContext = OperationContext.Current;
			MessageProperties mpMessage = opContext.IncomingMessageProperties;
			RemoteEndpointMessageProperty reMessage = (RemoteEndpointMessageProperty) mpMessage[RemoteEndpointMessageProperty.Name];

			strResult = string.Format("Processed Message from [{0}]:{1} ({2}): {3}",
				reMessage.Address,
				reMessage.Port.ToString(),
				opContext.ServiceSecurityContext.WindowsIdentity.Name, strArgument1);

			return true;
		}
	}
}

In this class, we first associate the class with the interface. This is done with the line public class IPCService : IIPCService. I then defined a ServiceHost variable to store the reference to the WCF host object. For this example, I’ve chosen to use the BasicHttpBinding class to describe the connectivity. This means that the HTTP protocol will be used for communications. There are other choices, but this was my preference. Note, using HTTP does not mean you need to install a web server (although you could host this in a web server as well). When the StartService method is called, the binding is created. When you create a binding, you need to specify the URI that your service will be accessible on. In this example I’ve used http://computername:50000/SampleWindowsServiceIPC. The breakup of this URI is as follows:

  • http:// – use HTTP.
  • computername – your computername goes here.
  • 50000 – the TCP port to listen on.
  • SampleWindowsServiceIPC – more or less an arbitrary name with the entire string unique to your application.

I’ve also enabled authentication on this binding, so that any caller of this service must authenticate using Windows credentials. There’s numerous other options for this, or you could simply enable anonymous access. It’s generally a good idea to attach an authentication rule to the binding, as this is a network service – it is accessible over the network, depending on your computer/network/firewall configurations etc. Additionally, if you are using authentication, its a good idea to encrypt the communications, which can be done with certificates (HTTPS), IPSec, etc.

One small caveat however, is that because we’re using LocalService as the service account, the service doesn’t have permission to register that binding on the system. There are numerous fixes for this, including granting LocalService permission to establish the binding, pre-establishing the binding, or using an alternate account with permission. I’d generally use a specific service account, and grant it permission to maintain the binding.

I’ve also updated the OnStop and OnStart functions from the service to start/stop the WCF component.

		protected override void OnStart(string[] args)
		{
			this.EventLog.WriteEntry(string.Format("Service {0} (v{1}) starting.", _strAppTitle, _strAppVersion));

			_oTimerLoop.Interval = 5000;
			_oTimerLoop.Elapsed += _oTimerLoop_Elapsed;
			_oTimerLoop.Start();

			IPCService.StartService();
		}

		protected override void OnStop()
		{
			this.EventLog.WriteEntry("Service stopping.");

			IPCService.StopService();
		}

And that’s it. The service will run and do whatever it needs to do. It will also host the WCF component which can interact with the rest of the service as required. You can see in the Function1 example above, I’m extracting the caller’s IP address, port and username.

The only thing to do now is create a small test application that calls the WCF function. This is the client application.

For this example, I’ve just created a simple Windows Forms Application. Add the service host reference again (System.ServiceModel.dll), and add a reference to the service application (to gain access to the interface). I’ve added a button and a textbox to the main form. Here’s the code we need (again, without error handling).

using System;
using System.ComponentModel;
using System.ServiceModel;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e)
		{
			ChannelFactory<SampleWindowsService.IIPCService> cfClient;
			BasicHttpBinding httpBinding;
			SampleWindowsService.IIPCService service;
			string strOutput = "";

			httpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
			httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

			cfClient = new ChannelFactory<SampleWindowsService.IIPCService>(httpBinding, "http://localhost:50000/SampleWindowsServiceIPC");

			cfClient.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
			cfClient.Credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;

			service = cfClient.CreateChannel();

			if (service.Function1("input", out strOutput) == true)
				textBox1.Text = strOutput;

			cfClient.Close();
		}
	}
}

Simple enough code, we create a http binding, attach the URI, specify the authentication method etc. The credentials of the current user are attached to the request. After that, we simply create a communications channel and call the function.

Personally, when I’m creating WCF functions I tend to make then return a boolean or integer based object. I use the returned object to determine success/failure of the call. I then use an out parameter to return data as required.

Pretty cool stuff and relatively simple to do. There’s a huge amount of other stuff you can configure with WCF, but I’ve tried to keep the example simple. It’s amazing what you can do with very little code these days, although it’s always best to understand what the code is actually doing, and keep security etc in mind.

~ Mike

7 thoughts on “Creating a .NET WCF enabled Windows Service with authentication in C#.

  1. The idea to add a timer so that we can put in some regular maintenance tasks is interesting:
    what about using it to actually test the connection to the WCF service and log it down to a file? Maybe each two hours, for monitoring purposes… will try.

  2. Great article. I’ve been creating WCF services for years. This is the best writeup I’ve seen, bar none. Your info on using the Installer is new to me: thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s