Nancy Unit Debugging Routing Error Details

Unit tests are something that are easier than ever with the Owin standard because everything is modular which make mocking easily. However, some basic output may be not as intuitive as we are used to be. For example, during unit testing routing I stumble into an error which say that the Http Status was to 500 instead of 200. No exception was provided. How do you get the exception that thrown the Http Status Code 500? The solution is to get the output of the Html and see the error.

First, if you are unit testing routing, you should use the Nancy.Testing Nuget’s package. This one give you a Browser object that allows to simulate an Http query. You can execute the path that you want to test by using the Get method. This return a BrowserResponse. Getting the status code is available by verifying the StatusCode.

// Arrange
var browser = new Browser(bootstrapper);
            
// Act
var result = browser.Get("/", with => with.HttpRequest());

// Assert
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);

The problem is when the assert fail. You do not have any indication of why the Nancy Routing failed. If you are debugging and that you check the BrowserResponse object, you will see a Body property but it is of type Byte[]. This type is not humanely understandable. The trick is to use the extension method AsString() to get the Html output and read the error message.

var html = result.Body.AsString();

That say, most of the time is that the app.config does not have the reference to Razor page. You just need to include the Nancy.ViewEngines.Razor and be sure that the app.config has the Razor configuration and you will be able to have a HttpStatus of 200.


  <system.web.webPages.razor>
    <pages pageBaseType="Nancy.ViewEngines.Razor.NancyRazorViewBase">
      <namespaces>
        <add namespace="Nancy.ViewEngines.Razor" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

Nancy FX’s Content Folder remains Routed

You created your brand new web application with Nancy (MVC Katana for Microsoft OWIN) and you want to use BootStrap. Nuget is working like all .Net project so you can get BootStrap. However, every time one of your page want to get BootStrap’s stylesheet you have this one routed into your NancyModule. This is wrong because Nancy default behavior is to not route any file from the content folder. The problem is that Nuget added BootStrap in the content folder BUT has not set the property to copy the file when compiling. The reaction of Nancy is that it cannot find the file, so it try to route it.

To fix this issue of not having BootStrap or any other content file routed, right click the files inside the content folder and click properties. Choose from the Copy To Output Directory the option named Copy Always. Recompile your application, launch the web project and you should be all fine.

CopyAlwaysContent

Unit Testing Nancy Routing, Controller and IoC

Maybe the title should be more integrating test with Nancy than unit testing because this is far more integrated than unit. However, the goal is to test and a NuGet package allow you to test easily test Nancy application. This NuGet package is called Nancy.Testing and can be installed with the following command.

Install-Package Nancy.Testing 

This allow to create a Browser (from the CsQuery.dll that is a dependency of the Nancy.Testing.dll) object that will act like a client to the Nancy server. From there, you create a unit test like usual and use the browser object to request to a specific url. Here is an example that request the base page (no page just the localhost). We expect to have a default webpage that return a 202 status.

[TestClass]
public class IndexModuleTest
{
    private readonly Browser browser;
    public IndexModuleTest()
    {
        var bootstrapper = new NancySelfHostedWithSignalR.Bootstrapper();
        browser = new Browser(bootstrapper);
    }

   [TestMethod]
   public void GivenDefaultUrl_WhenMarkdownListReturnData_ThenIndexPageLoad()
   {
       var result = browser.Get("/", with =>
       {
           with.HttpRequest();
       });

       Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
    }
}

One problem that you may stumble into is that the IoC of of BootStrapper is using some of the class that you may want to mock. This will require you to create a new Bootstrap and to override your default configuration. Instead of having multiple BootStrap class, we can have one for test where we can push all the mock required for each test. Imagine that you have a BootStrapper that define a lot of Interface to concrete type inside the ConfigureRequestContainer method. What you have to do it to override at your turn of your own Bootstrapper and override too the ConfigureRequestContainer. However, you call the base method before your testing ones. This way, it will override the one you redefine with your mock when testing.

private class TestingBootstrapper : YourDefaultBootstrapper
{
    public List<Tuple<Type, object>> Types { get; set; }

    public TestingBootstrapper(List<Tuple<Type, object>> types)
    {
        this.Types = types;
    }

    protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
    {
        base.ConfigureRequestContainer(container, context);
        //Override here for test
        foreach (var typeInterfaceAndImplementation in this.Types)
        {
            container.Register(typeInterfaceAndImplementation.Item1, typeInterfaceAndImplementation.Item2);
        }
    }
}
// Later inside one of your test:
var types = new List<Tuple<Type, object>>();
var bootstrapper = new TestingBootstrapper(types);
            
var mock1 = new Mock<IFile1>();
mock1.Setup(...);
types.Add(new Tuple<Type, object>(typeof(IFile1),mock1.Object));
var browser = new Browser(bootstrapper);

The browser uses your testing bootstrapper and in the same time redefine only the interface that you want for your test. This is interesting if you want to reuse a big part of your existing bootstrapper. Otherwise, you can just use the lambda action method to define your classes.

 var browser = new Browser((c) => c.Module<IndexModule>().Dependency<IFile1>(mock1.Object))

Nancy Configuration of IoC for Module

Nancy module constructor is by default without parameters. However, soon you will need to have your route match to some of your logic which should be under some business logic classes. In fact, the next step after routing should be to call your controllers or or service layer classes. To be able to inject your service layer class, you need to inject this class. Nancy Bootstrap class come to the rescue. You only need to override a single method to be in business. Nancy comes with a default small IoC. The method to override is named ConfigureRequestContainer.

public class YouBootstrapper : DefaultNancyBootstrapper
{
    protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
    {
        base.ConfigureRequestContainer(container, context);
        container.Register<IServiceLayer, YourServiceLayer>();
    }
}

After this modification, you only need to remove the parameterless constructor and have the one with the interface defined in the request container of the BootStrap class.

public class IndexModule : NancyModule
{
    public IndexModule(IServiceLayer serviceLayer,
}

Concerning the boot strap class, Nancy will load automatically your class by scanning the assembly where you startup class reside.

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.