How to easily create self hosted signalr windows service using TopShelf framework

Recently i got the chance to work with windows service. As a web developer i have never created windows service in my carrier. Generally i used to refer MSDN and hence i was trying to understand the flow of windows service from MSDN. But for more complex example i did some googling in detail and found out “TopShelf” library.

Topshelf is an opensource windows service framework written in c#. Using TopShelf creating windows service is as easy as creating a console application. This framework will literally convert your console application into windows service. What!.. yes, you heard it correct. You can easily convert your typical console application into windows service and easily debug it and install it in “Service control manager” by using few lines of Topshelf’s configuration fluent API. It’s available on GitHub. Okay, in this blog post we’ll step-by-step create self hosted signalr server in windows service and consume it in another console application.

So before we go ahead, let’s understand what signalr is in brief. Well, SignalR is a library for a developer which allows real time bi-directional communication between server and client. Means using SignalR, server can broadcast its message instantly to the connected specific / all clients.

Now its time to do some code. First let’s create a blank solution project in visual studio. Now add one console application in that solution and name it – “SignalRServerUsingTopShelf“. Now add “TopShelf” dll from nuget as shown in below image.

NugetForTopShelf

Also Install Log4Net from nuget which is an open source library that allows application to log statements to a variety of targets

Note: Before you install TopShelf, your console application’s target .net framework must be 4.5.2 or greater.

Now let’s add “StartUp.cs” class to configure signalr middleware. This class contain “Configure()” method. In this method we call “MapSignalR()” method which defines the root that client will use to connect our Hub. To allow cross domain request we set CORS middleware.


public class StartUp
{
	public void Configuration(IAppBuilder app)
	{
		app.UseCors(CorsOptions.AllowAll);
		var hubConfiguration = new HubConfiguration
		{
			EnableDetailedErrors = true
		};

		app.MapSignalR(hubConfiguration);
	}
}

Let’s create signalr hub class. This class contain methods which allows real time communication between server and client. You can think of this class as a mediator between server and client.


public class MyMessageHub : Hub
{
	//public static Dictionary<string, string> subscribedClients =
       //                 new Dictionary<string, string>();

	public void BroadcastMessage(string message)
	{
		Clients.All.BroadcastMessage(message);
	}
}

Now let’s add one new class named it – “SignalServer.cs” in which we write our core windows service related function and will later configure this class using TopShelf’s configurable API in program.cs file’s Main() method. Generally typical windows service class contains method like OnStart, OnStop, OnPause etc. which determine what happens when the state of your service is changed. So in our case the “Start” method contains the defining and hosting of signalR server when my service will start and in “Stop” method i want to dispose the require resources which i have created on start method.


public class SignalRServer
{
	private ILog logger;

	IDisposable SignalR { get; set; }

	public SignalRServer(ILog logger)
	{
	     this.logger = logger;
	}

	public bool StartService()
	{
		logger.Info("Starting service...");
		var option = new StartOptions();
		//option.Urls.Add("http://localhost:18275");
		// You can either get dynamic ip OR set in app.config
		// But for demo purpose i have set it static
		option.Urls.Add("http://192.168.151.87:18275");
		SignalR = WebApp.Start(option);
		logger.Info("SignalR server started..");
		logger.Info("Service Started.");
		return true;
	}

	public bool StopService()
	{
		SignalR.Dispose();
		logger.Info("Service Stopped.");
		System.Threading.Thread.Sleep(1500);
		return true;
	}

	public bool PauseService()
	{
		logger.Info("I'm in Pause method");
		return true;
	}
}

Now its time to configure our “SignalServer.cs” class using TopShelf’s fluent API in program.cs.


class Program
{
	private static readonly ILog logger =
		LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

	static void Main(string[] args)
	{
		logger.Info("Programe launched");
		HostFactory.Run(config =>
		{
			config.Service(instance =>
			{
				instance.ConstructUsing(() =>
					new SignalRServer(logger));

				instance.WhenStarted(server => server.StartService());

				instance.WhenStopped(server => server.StopService());
			});

			config.SetServiceName("Signal_server");
			config.SetDisplayName("Signal server");
			config.SetDescription("Self hosted signal server using TopShelf");
			config.StartAutomatically();

			config.BeforeInstall(() =>
			{
				logger.Info("Service before install");
			});

			config.AfterInstall(() =>
			{
				logger.Info("Service after install");
			});

		});
		//Console.ReadLine();
	}
}

I guess no need to explain the above code as you can see in the above code, Just like normal windows service i have configured the start and stop method and set the service name etc. using TopShelf’s API. Now its time to run the code. Just press “F5” in vs and you can run it as normal console application. When you run the application, it’ll open this type of console window.
Output

Before we go ahead please take one note here – in SingalR when you specify ip address in url (refer SignalRServer class – StartService method) and while running the application sometimes it throws an exception of – “TargetInvocationException“. To get rid of that exception we need to register that url using “Netsh” command. Open command prompt in admin mode and type

— To Register url
netsh http add urlacl url=http://192.168.151.87:18275/ user=EveryOne

— To deregister url
netsh http delete urlacl url=http://192.168.151.87:18275/

netsh_addUrl

Now let’s install our service in “Service control manager” using topshelf command line utility. Go to bin/debug folder and copy the path. Now open command prompt in admin mode and paste the copied path and press enter. Then after enter below command –

“YourServiceName” install start

Topshelf will install the service and showing the following output which means your normal console application now works as a windows service.

Service_Install

You can verify it by opening service manager window.

HostedService

Uninstalling of the service is also easy. Just type following command in command prompt.

“YourServiceName” uninstall

UnInstall_Service

This demo application source code is available for download on GitHub where i have added two more console app from which one works as message sender and another one works as message receiver. That’s it for now. Hope you like this post.