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 signalr Hub. To allow cross-domain request we set CORS middleware. But before that, you need to add the reference of Microsoft.AspNet.SignalR and Microsoft.Owin.SelfHost along with some other NuGet packages to our console application as shown in below image.

NuGetPackageList


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 contains methods which allow 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 a 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 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.

6 thoughts on “How to easily create self hosted signalr windows service using TopShelf framework

  1. I might have missed it but I can’t see where you tell us what references are required to use SignalR. The standard console application project template does not support SignalR and I don’t think TopShelf brings it in either.

    Like

    • Yes, That’s correct that the standard console app template doesn’t come-up with the singalr by default. So for that, you need to add the reference of singalr from Nuget. I have updated my blog post and added the screenshot of nuget package reference. By-The-Way I have already added the Github link in the last paragraph of this blog post. Just download my sample application from there and play with it. Thank you.

      Like

  2. The sevice is working fine for me for both localhost and ip addresses, but when i am trying to access it from public network, it is not working. when I am trying to access myServerIpAddress:8083/signalr/hubs, from public network, it says “This site can’t be reached”.

    Like

    • Suhail,

      l assume here you are in intranet. Let say your ip address is 192.168.100.131. So you need to add that ip address into host file where you tried to access signalr link. Host file is found at – “C:\Windows\System32\drivers\etc\”. Let me know if you have any further query.

      Like

  3. I have noticed you don’t monetize your page, don’t waste your
    traffic, you can earn extra cash every month. You can use the best
    adsense alternative for any type of website (they approve all websites),
    for more info simply search in gooogle: boorfe’s tips monetize your website

    Liked by 1 person

    • @BestRandall – Thanks for this advice. Yes, as traffic grows on my blog, i am thinking of to monetize my pages. But i guess for that i also need to upgrade plan of wordpress, as right now i am using free plan. 🙂

      Like

Leave a comment