Home » Web » Owin » Owin platform with Nancy and Signalr

Owin platform with Nancy and Signalr

Here is the context. Imagine that you have to host a web content in someone computer that does not have IIS. How can you do it? It exists multiple solutions from Node.js server to having a JavaScript only solution. However, if you have a lot of code already done in .Net and want to reuse that code, something else exist. In fact, what the solution exist since few years. Microsoft has the project Katana with the goal of removing hard dependencies on different web modules like we have with Asp, Asp.Net Web Form and Asp.Net MVC. An open standard called Owin emerged from that project. Owin means Open Web Interface for .Net. It goals is to create new components that can be easily developed and consumed but also create applications that could be more easily ported between hosts and potentially entire platforms/operating systems.

In this article, I will show you how to start with Owin to host inside a console a web server. We will use Nancy to be able to render Asp.Net MVC and use Signalr to have some real time update. The project will be very simple so you will not see the full potential but you will be able to do few things like displaying a razor page (.cshtml), use static resource like images for some images in a specific folder and handles all others with your code, get a real time notification when a client connect to the system and be able to notify from the server to the client content with Signalr.

Nancyvisualstudiotemplate

First of all, we need to create a solution with a project. One way to do it is to start with Nancy template. You can search for Nancy in Visual Studio and choose a template. Let’s choose “Nancy Empty Application with ASP.NET hosting and Razor”. This will come with some references that we will change but it will give us some of the stuff to work with. First thing to do is to remove the Nancy.Hosting.Aspnet. The reason is that Nancy come with its own self hosting environment, based on Owin but we want to use the generic one. The reason is that we will not only use Nancy but Signalr. So we will use the Owin bootstrap and attach in the pipeline Nancy and Signalr. We can uninstall with the Package Manager Console:

Uninstall-Package Nancy.Hosting.Aspnet

Then, let’s install some packages. First, the Owin host (generic one). Second, SignalR core library and the JS one that allow the view to connect to the backend. Third, we need to use the Razor View engin of Nancy. This differ a little bit from Asp.Net MVC Razor. We cannot use the Asp one because it has dependencies on the Asp stack. Forth, is the Cors package that allow us to do cross-domain call. This is required by SignalR.

Install-Package Microsoft.Owin.Host.SystemWeb
Install-Package Microsoft.Owin.Hosting
Install-Package Microsoft.AspNet.SignalR.Owin
Install-Package Microsoft.AspNet.SignalR.JS
Install-Package Nancy.Viewengines.Razor
Install-Package Microsoft.Owin.Cors

Before continuing, be sure that you are targeting the latest .Net Framework. I have set mine to 4.5.2, 4.5.1 works too but 4.0 fail on some packages. Also, verify that you have the latest package for all Owin libraries. You can get a list of the package that are not updated with that commands:

Get-Package -updates 

The next step is to create the console that will host the process. Keep in mind that you could create a Windows Service too or any other kind of container to host your Owin solution.

class Program
{
	static void Main(string[] args)
	{
		var url = "http://+:8080";

		using (WebApp.Start<Startup>(url))
		{
			Console.WriteLine("Running on {0}", url);
			Console.WriteLine("Press enter to exit");
			Console.ReadLine();
		}
	}
}

This code start the web application host at the post 8080. You can use what ever port you want. The important information is the line with WebApp.Start. It takes a type of startup project. This is the core of the configuration about what we are going to host. In our case, we will host for Nancy and Signalr. Here is the configuration class.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app
        .Map("/signalr", map =>
        {

            map.UseCors(CorsOptions.AllowAll);
            var hubConfiguration = new HubConfiguration();
            map.RunSignalR(hubConfiguration);
        })
        .UseNancy();
    }
}

Two important configuration. The first one is Signalr that allow to use Cors (cross origin references) and the second is Nancy. It is important to notice that SignalR has been defined first. This is because in the request pipeline, we want Signalr to be the first to verify if it can handle the request, and then Nancy. The reason is that in the application I am doing, I want to catch all URL and do something with them. I do not want to catch specify SignalR calls.

Nancy requires to have a bootstrapper class.

public class Bootstrapper : DefaultNancyBootstrapper
{
    protected override void ConfigureConventions(NancyConventions nancyConventions)
    {
        base.ConfigureConventions(nancyConventions);
        nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("Scripts"));
    }
}

If you define a class that inherit from DefaultNancyBootstrapper, the system will use it. Here we can define a directory that Nancy will not handle request from. This is how to say to Nancy to do not take care of the JavaScript requests. By default, Nancy does not handle static files from the Content folder. However, for the Scripts folder, you must add this one with the StaticContentsConventions.

It is important to note that Nancy will catch all extensions. See the web.config file. You should see that by default, the HttpHandler configured use all path. If you open the web.config and this is not the case, you should add these two configurations. This will allow you to handle every call. For example,

http://localhost:8080/your/path/to/action
or
http://localhost:8080/your/path/to/action/test.png
but not
http://localhost:8080/content/image.png
or 
http://localhost:8080/scripts/jquery.js
<system.web>
    <httpHandlers>
      <add verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
    </httpHandlers>
</system.web>
<system.webServer>
    <handlers>
      <add verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
    </handlers>
</system.webServer>

The next thing to do is to define Nancy’s modules. This is like defining Asp.Net Mvc routing in the same time of defining your Asp.Net Controller.

public class IndexModule : NancyModule
{
    public IndexModule()
    {

        Get[@"/{uri*}"] = parameters =>
        {
            var regex = new Regex(@"\.(png|gif|jpg|jpeg)$");
            if (regex.IsMatch(parameters.uri))
            {
                return View["image"];
            }
            else
            {
                return View["content"];
            }
        };
        Get["/"] = parameters =>
        {
            return View["index"];
        };
    }
}

Every routes has a priorities depending of the routing syntax used and order. In that case, I want to handle every images (which are not in the content folder, remember!) and also all other routes that will be for content. I also define a second route for the main web page. This is a case of using Owin/Nancy to handle images. Let’s say that you have some logic for dynamic image or for image that are not on the server but somewhere else. This way you can have your Http Image Handler withing your code.

The next step is to enable Signalr. This is to add the capability to the server and webpage to communicate. The code will not do a lot of thing here but in fact can update the content in real time. First, in the backend you need to create a class that inherit from Hub.

public class ExchangeHub : Hub
{
    public void Init(string urlHere)
    {
        Console.WriteLine(urlHere);
    }

    public void SendDataToClients(string data)
    {
        Clients.All.UpdateContent(data);
    }
}

This will generate by default some JavaScript code to all the client to call the server. The Init function all to send from the client side a string to the server. What we will do is when the page finish to load to call the server. The server can after that use the SendDataToClients to send some data back the the client.

The JavaScript file that need to be inserted inside your cshtml file should look this way:

<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/jquery.signalR-2.1.2.js"></script>
<script src="http://localhost:8080/signalr/hubs"></script>
<script type="text/javascript">
    $(document).ready(function () {
        //Set the hubs URL for the connection
        $.connection.hub.url = "http://localhost:8080/signalr";

        // Declare a proxy to reference the hub.
        var chat = $.connection.exchangeHub;

        // Create a function that the hub can call to broadcast messages.
        chat.client.UpdateContent = function (data) {
            alert(data);
        };

        // Start the connection.
        $.connection.hub.start().done(function () {

            // Call the Send method on the hub.
            chat.server.init("url here");


        });
    });
</script>

First, we need to define in that specific order three scripts. The first one is JQuery, the second one is Signalr and the third one is the Signalr hub that has been automatically generated.
After, we connect to the server hub and we get the exchangehub that come from the proxy file generated and we setup what happen when the server call the update content. In this example, we just alert the message. Finally, we send a request to the server when the page is finally loaded and that the hub is ready (connection is established between client and server). You can find the source code into this Git repository.

If you like my article, think to buy my annual book, professionally edited by a proofreader. directly from me or on Amazon. I also wrote a TypeScript book called Holistic TypeScript

7 Responses so far.

  1. WillT says:

    Lots of inconsistencies or article isn’t complete?

    You forgot to mention that you need to install SideWaffle to get those templates. Once installed you could just select the template that doesn’t have the ASP.NET hosting in order to skip the removal of it in the next step. From there you forgot to add that you need to all install the package Nancy.Owin, or your project doesn’t even build.

    Moving to your code, you call it self hosted, but it’s using OWIN not the Nancy self hosted stuff, although curiously you do have it installed (but you’re missing the HttpListener). Your code doesn’t seem to use any of the above steps as it isn’t even a web project, it is a console app as it correctly goes into the Program main method to ramp up a server. Maybe you switched half way through? You have both a app.config and a web.config so maybe that’s the case.

    Trying to run the app, you forgot to mention that you’ll need to be running VS as an administrator. Running the app, now I’m getting path errors as it seems to be looking for files within the bin/Debug folder. I’m currently looking in how to fix that. Ugh.

    • Hello Will,

      First, thank you for your comments. I will bring some more information. I do not remember at that time if Nancy was pre-installed or not but I do not recall (that is 1 year ago) to have installed SideWaffle.

      Self-hosted because it ran in a Console, not with IIS or any other software — it is hosted with your .exe. About the web/console confusion, as I re-read this article, it seems that my objective was to host the OWIN host and not Nancy’s one.

      I have not give the information about running as administrator since I run always VS in administrator. My bad.

      • WillT says:

        Well I guess it got me somewhat started, but I’m having to do a lot of leg work, which is fine, but I just read this thinking that this was the answer.

        There’s no other way that I know of to get those templates installed. It isn’t with the default installation of VS I’m 100% positive.

        Yes, that’s correct, it’s an OWIN host, using Nancy to serve up views. Nancy has a self hosted way of doing things too which is somewhat similar but not the same. Creating the Nancy project creates a web.config and a web project. I don’t think I’d go down this path at all as you need a console project.

        Marking all of the static files to “Copy Always” or “Copy if Newer” copies the files to the same path as the exe which seems to solve most of my problems, although I can’t figure out how to get typescript files over (which is outside the scope of this article).

        Hopefully my comments save someone else some time. This stuff is all new to me. I guess the good thing is that me having to research everything is getting me up to speed quickly, but then again I don’t have a lot of time and need to get this out the door yesterday.

        • I am really grateful of you comments and will improve my next articles. With some retrospective, I feel you are very right on a lot of points you brought. I feel that I was in a hurry when I write it and didn’t get enough in details. Thanks for your time, like you said, it will probably help someone else and that is very nice of you.

  2. WillT says:

    Also, not sure what SignalR even does in this example. Sends a message to the console upon loading the default NancyFx screen? Very confusing.

    • This is not a real application. It does nothing else than be there and get a message from the Client side on the Server side console. From there, you can do what ever you want with SignalR. I am sorry to have confuse you. This article didn’t mean to be extra-detailled but more as a gist of being able to host a webserver with Owin/Nancy.

      • WillT says:

        In your code you have half of the “Chat” application that comes with the default SignalR examples. Except then the Nancy view has nothing on it to show. It probably would have been minimal work to continue with the chat example, and having that on the page. I browsed that quickly as I didn’t care about the SignalR stuff and was wondering why on earth I was looking at a default Nancy screen.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.