Windows Services Using C# – Creating a Service

Have you ever wanted to create a Windows service that ran in the background taking on tasks you wanted to offload from your main application or maybe perform periodic maintenance on a schedule you set? Windows services are a great way to do this.

Windows services are very versatile in that not only can they be run as a service, they can be run under a console host and even under IIS. Each of these have unique advantages which will be presented through this series.

The first part in this series is how to create a backend service using C#. To make this simple and straight forward, details regarding every aspect of the solution provided will not be explored. The focus of this part of the series will be creating the service project and getting the code in place so the service can be installed as a Windows service. Included in the solution is a Windows Forms Application (TestConsole) used to connect and test the functionality of the service but we will not discuss that in this post.

Let’s get started!

First things first. Microsoft Visual Studio 2013 and .NET Framework 4.5.1 is being used but other versions will work as well. Visual Studio 2010 and .NET Framework 3.5 was used previously without issue. The steps may be a little different but all should work without issue.

Instead of creating a project from the start, I have found it best to just create an empty solution and then add the projects to the solution as needed. This allows you to create the solution file with the name you want and then create each project file with a name you want. In this case I created a blank solution with the name of ServicePart1. This can be done by going to File | New | Project or Ctrl + Shift + N, selecting the Installed | Templates | Other Project Types | Visual Studio Solutions | Blank Solution, entering ServicePart1 as the name of the solution, and clicking OK button.

Next you will create a new project under the solution by right clicking on the Solution in the Solution Explorer tool window, selecting Add | New Project…, selecting the Installed | Visual C# | Console Application, entering MyService as the name of the project, and clicking OK button. At this point you will need to add a new reference to the MyService project by right clicking on the References under the MyService project and selecting Add Reference… Locate the System.ServiceModel under the Assemblies | Framework list and add it as a reference.

Next we will create an interface that will be used to access the service. This is used on the service and client side and defines the contract between the two. For simplicity we will create the interface in the MyService project and reference this project in the TestConsole project to gain access to this. Note there are other ways to do this that are more effective at separating out the different concerns of the solution and we may do that in another post. Create the IMyService (funny name but this is just kicking the tires type stuff and keeping naming consistent) interface by right clicking on the MyService project, selecting Add | New Item…, selecting the Interface item, changing the name to IMyService.cs, and clicking the Add button. Note to make this accessible to external projects the public attribute must be added on the interface. I am not really sure why they did not make this the default since in many cases the interface is intended to be a public means of accessing items. While we are here, we will create an add function in the interface. Also, we have to add the System.ServiceModel using so we can add the attributes to make the interface available as part of the service. The code should look like the following.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
 
namespace MyService
{
   [ServiceContract(Namespace = "MyService")]
   public interface IMyService
   {
      [OperationContract]
      int Add(int nNum1, int nNum2);
   }
}

To add the functionality to the service a class needs to be implemented that supports the interface above. Follow the same steps as with the IMyService interface except select the Class instead of Interface. Also the name of the class will be MyService for consistency purposes. We add the interface and code to support the interface so that this object can be used to provide the functionality for the service. The code should look like the following.

class MyService : IMyService
{
   public int Add(int nNum1, int nNum2)
   {
      return nNum1 + nNum2;
   }
}

Now let’s get to some fun stuff! To keep things simple we are going to create a generic AppServiceHost which will allow us to provide the interface and object and let it handle all of the nasty work of setting up the service. Since we are just trying to get our feet wet with services in this post, this will be very simple and will only handle a NetTcpBinding and will be hard coded to the machine the service is running on with a port of 64000 and name of MyService. In another post we will explore making this more versatile by adding Http and Https bindings and a more dynamic way of setting up the service without having to modify the code. To do this we will create a class (by now you know how to do this, right :-)) and name it AppServiceHost. We add the generic code and constructor for the object such that it will allow us to reuse this object for any service we want to create without having to write it specifically. Below is the code that needs to replace the class information that was automatically created.

public class AppServiceHost<I, T> : ServiceHost
{
   public AppServiceHost(string sConfigFilename) : base(typeof(T))
   {
      // First we setup the service end point information for use below
 
      string sServiceEndPoint = string.Format("net.tcp://{0}:64000/MyService"Environment.MachineName);
 
      // setup TCP endpoint
      //...................
 
      NetTcpBinding oNetTcpBinding = new NetTcpBinding(SecurityMode.Transport);
 
      ServiceEndpoint oServiceEndpoint = this.AddServiceEndpoint(typeof(I), oNetTcpBinding, sServiceEndPoint);
 
      Console.WriteLine("TCP endpoint created: " + sServiceEndPoint);
      Console.WriteLine();
   }
}

Now that we have the MyService object with an interface and the generic AppServiceHost we need to create our MyServiceAppService object that handles the creation of the service and provides the service name along with the start and stop processes for the service. This object is what gets registered for the service when installing our service. To do this, we will create a Windows Service object. Same procedure as above only you will select a Windows Service from the list and name it MyServiceAppService.cs. Once you have this the following code is what needs to be setup in order to make the object useful.

partial class MyServiceAppService : ServiceBase
{
   AppServiceHost<IMyServiceMyService> m_oAppServiceHost = null;
 
   public MyServiceAppService()
   {
      InitializeComponent();
 
      ServiceName = MyServiceName;
   }
 
   protected override void OnStart(string[] args)
   {
      m_oAppServiceHost = new AppServiceHost<IMyServiceMyService>();
      m_oAppServiceHost.Open();
   }
 
   protected override void OnStop()
   {
      m_oAppServiceHost.Close();
   }
 
   static public string MyServiceName { get { return "My Service"; } }
}

Now that we have the parts in place we need one last thing to pull it all together for installing the service and getting it up and running. To do this, we will create an Installer Class named MyServiceAppServiceInstaller.cs using the same process as before. We add the following code so that it will have the code for installing the service we just created.

[RunInstaller(true)]
public partial class MyServiceAppServiceInstaller : System.Configuration.Install.Installer
{
   public MyServiceAppServiceInstaller()
   {
      InitializeComponent();
 
      // This installs the service and sets the service to automatically startup.
 
      ServiceInstaller oServiceInstaller = new ServiceInstaller();
 
      oServiceInstaller.ServiceName = MyServiceAppService.MyServiceName;
      oServiceInstaller.StartType   = ServiceStartMode.Automatic;
 
      Installers.Add(oServiceInstaller);
 
      // This sets the process to run under the local system account.
 
      ServiceProcessInstaller oServiceProcessInstaller = new ServiceProcessInstaller();
 
      oServiceProcessInstaller.Account = ServiceAccount.LocalSystem;
 
      Installers.Add(oServiceProcessInstaller);
   }
 
   public override void Install(IDictionary oSavedState)
   {
      base.Install(oSavedState);
   }
 
   public override void Uninstall(IDictionary oSavedState)
   {
      base.Uninstall(oSavedState);
   }
}

Now lets get this new service installed so we can start testing it out. To do this you will run the InstallUtil as an Administrator on your machine passing the application in as the only argument. You can find more information about the InstallUtil at the following location https://msdn.microsoft.com/en-us/library/sd8zc8ha(v=vs.110).aspx. The easiest way to do this is locate the Visual Studio Tools Command Prompt in the Start menu under All Apps | Visual Studio 2013 | Visual Studio Tools. Right click on the correct command prompt (e.g. x64 or x86 depending on your machine) and select Run as Administrator. This will bring up a command prompt window for you to execute the InstallUtil process. Note if you do not run the command prompt as an Administrator you will most likely get an error and the service will not be installed. Now that you have the command prompt window open as an Administrator we change to the location where the MyService.exe is located. This will be in the ServicesPart1\MyService\bin\Debug directory. Once you have changed to the directory where the MyService.dll is located you will execute the InstallUtil MyService.dll command and the service will be installed. If you get a message indicating “The transacted install has completed.” then you will be set to go. This can then be verified using the Control Panel | Administrative Tools | Services application and locate the My Service in the list of services. By default the service does not automatically start up. So if you want the service to run you will use the Control Panel to start the service for now. Note it is set to automatically start and will do so when the machine is rebooted.

Now that you have all of that setup you want to test this thing out. To make all of this simple I provided the code so that you can download the full solution, build it and run the TestConsole provided against the service. Since the focus of this post was to create a service we will not be going into the TestConsole in this post. We will save this for another post where we will expand the TestConsole and get into more of the nitty-gritty details of providing functionality such as error handling and other fun stuff. The code can be downloaded from ServicesPart1 which has both the MyService and TestConsole applications.

I hope you have found this post interesting and of value. Feel free to leave a comment regarding this and stay tuned for future posts where we will begin refining this more and getting into a more details about other aspects of Windows services. Have an awesome day!

Durant Rodrigue