Using Nancy to Remotely Control a Desktop Application

I recently had the requirement to control a desktop application from a mobile device. The application, written using Windows Presentation Foundation (WPF) uses the secondary monitor of a system in full-screen mode, generating views that are shown on projection screens in a sports arena. More on the background story in a later blog post. [Update: the post is now online]

When I write “control” I mean that I wanted to be able to

  • see a preview of the 10-30 possible views; the views are rather static, so a static preview with a manual refresh is sufficient.
  • tap a preview picture and make the application show the corresponding view on the projection screens

The “mobile device” should not be limited to a specific platform, so the least complicated solution that came to my mind was to let the desktop app host “something” that would let me open a web page in a mobile browser. The web page could show the preview pictures, tapping one of the pictures would use some JavaScript to call a specific URL (without navigating away from the web page).

So the requirements were:

  • http://hostname:port/ returns the HTML for the web page
  • http://hostname:port/images/filename.jpg returns a picture used by the web page
  • Calling http://hostname:port/commands/show/provider/view tells the desktop application to show a specific view generated by a specific provider.

If you search the web for e.g. “wpf web server self-hosting”, you’ll sooner or later come across various recommendations, with the name Nancy popping up here and there. The Nancy framework advertises itself as follows (quote):

Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .Net and Mono. The goal of the framework is to stay out of the way as much as possible and provide a super-duper-happy-path to all interactions.

In this blog post I’ll give some tips for using Nancy in the scenario I’ve outlined above, but please don’t expect ready-to-use code.

How to get Started

The Nancy website is at http://nancyfx.org/. Don’t be put off by the black background, just take a look at the small code snippet for a hint on the overall experience.

The NuGet packages you’ll need are Nancy itself (of course) and Nancy.Hosting.Self.

The next stop is the documentation; after reading the Introduction I headed straight to Self Hosting Nancy – this was looking promising enough in terms of simplicity to keep me going.

Do not ignore the section HttpListenerException, i.e. don’t stop reading at “may be thrown”, understand it as “will be thrown”. The netsh command line in the documentation is for a specific user, in my scenario I wanted anybody (in the heavily restricted network) to be able to access. In this case you’ll need the following command line (replace port with the actual port number):

netsh http add urlacl url=http://+:port/ sddl=D:(A;;GX;;;WD)

How you’ll proceed from here depends on your personal style. Combining the code snippets from the Introduction and Self Hosting pages will give you a first feeling of success with “Hello World” appearing in your browser.

General Remarks on (Learning) Nancy

The Nancy framework is simple to use, but that doesn’t mean you get around learning the basics. Two recommendations:

  1. If you share my feeling that the Nancy documentation has the tendency to dive into the specifics a bit too fast (which later may be great, usually framework docs are too shallow), read the article “Understanding Nancy – Sinatra for .Net”. I found it very helpful because it explains the core terms in a very concise way.
  2. Not a groundbreaking insight, but true nevertheless: If you learn a new framework, set breakpoints everywhere to learn the life cycle. It is especially important to know what gets instantiated when and how often.

Some Remarks on Self-Hosting in an Existing Application

  • I had trouble getting the Razor view engine to work, searching the web I had the feeling that I’m not alone. I didn’t dig much deeper as the “Super Simple View Engine” does everything I needed.
  • When you self-host in a desktop application and want an incoming call of a URL to have an effect on the GUI, keep in mind that the GUI can only be updated from the UI thread. In the case of WPF, you’ll have to use on the Dispatcher.BeginInvoke pattern, e.g.
    Application.Current.Dispatcher.BeginInvoke((Action) (()=>
        {
            // Update UI
        }));
  • My application uses the Managed Extensibility Framework (MEF) and I needed a specific application service (IRemoteAccess) inside a Nancy module. The “Nancy-way” to pass something to a Nancy module (that is instantiated for each request) is to use dependency injection (DI) via a constructor parameter. Nancy uses an IoC container called TinyIoC for DI and bridging the world of MEF and TinyIoC isn’t complicated. If you use Nancy, you’ll sooner or later have a “bootstrapper” class that is used for tweaking things in Nancy – that’s where you can e.g. put stuff you’ll need later into the TinyIoC container:
    public class RemoteAccessBootstrapper : DefaultNancyBootstrapper
    {
        public static CompositionContainer MefContainer { get; set; }
    
        protected override void ApplicationStartup(TinyIoCContainer container,
                                                   Nancy.Bootstrapper.IPipelines pipelines)
        {
            // …
    container.Register(MefContainer.GetExportedValue<IRemoteAccess>()); } // ... }

The Web Client

The project was a spontaneous idea with a very tight deadline, so the “client” is a single static web page. Tapping on one of the preview pictures is supposed to access a specific URL without navigating away from the page. In the spirit of “the simplest thing that could possible work” I used the following bit of JavaScript code I found on StackOverflow:

function show(provider, view) {
    var i = document.createElement("img");
    i.src = "commands/show/" + provider + "/" + view;
}

Over the summer the client will be rewritten completely as a single page application, inspired by the article “AngularJs, NancyFx, TypeScript, and BootStrap Oh My!”. The goal is to include more sophisticated features in the client and have learn new technology along the way.

Final Verdict

In the short time I had available I didn’t do thorough research what could be the best solution to my problem, but what I can say is that Nancy did its job well enough I can recommend it – at least for this specific scenario.

Nancy kept the promise of simplicity, but at the same time I always had the feeling whenever I needed “more”, there was a way for me to customize / tweak it without jumping through hoops.

Nice one!

No Comments