Running ASP.NET on a Raspberry Pi with Mono and OWIN

Raspi_Colour_RIn the light of the announcements we made last week during the Connect() event, on open-sourcing the .NET server stack, I got curious what it would like be to run .NET on Linux. At home I’m using a couple of Linux based devices, including a Raspberry Pi Model B. Using the open source Mono project, getting a typical Hello World .NET application running on the Raspberry Pi isn’t much of a challenge. So I figured out it would be cool if I could use the little Pi to run ASP.NET code, which opens up a whole range of possibilities (including using the Pi as an “internet-of-things gateway” to connect my family of Arduino’s securely to the cloud, more on that later).

It turned out to be pretty straight forward! And due to the overwhelming number of requests 🙂 I decided to write down all the steps needed to create a basic .NET Console Application hosting ASP.NET code and running it on a Raspberry Pi. If you want to test out the code immediately, you can get the sample from my GitHub.

Step 1: Get Linux running (headless) on the Raspberry Pi

rasp_aspnet_writingimgThe first thing you need to do get a Linux distribution running on your Raspberry Pi. There are many choices and I choose for the Arch Linux distro. Basically because it’s a pretty light distribution (in terms of size and included apps) and you can run it headless (without a screen attached) very easily. So download the zipped version of Arch Linux for the Raspberry Pi image(1), and extract the single IMG file it contains. The next step is to write the IMG file to a SD card which will be used by the Raspberry Pi to boot from. If you are running Windows on your dev box like me, you can download and install the Win32 Disk Imager tool, if you are running Linux you need to follow the slightly longer instructions. Writing the image is with Win32 Disk Imager easy, just select the IMG file and select the location of your SD card, and then click Write.

Once the writing is done, insert the SD card into the Raspberry Pi, plug in a network cable and give it some power via the micro USB port. Now the Raspberry Pi is going to boot from the image you just wrote on the SD card. Give it a couple of minutes and then check if you can ping the device using the default host name alarmpi. Alternatively you can check your router’s DHCP client list to see if the Raspberry Pi shows up over there.

Step 2: Configuring Arch Linux

rasp_aspnet_sshOk, now we are ready to connect to the headless Raspberry Pi using SSH (which will basically open a remote command line). To do this, you need a SSH client, once again there are many, many choices. Putty is a pretty popular client, but I like the Bitvise SSH Client a lot, so that’s the one I’ll be using in this step-by-step guide. Once you’ve installed your SSH Client of choice, fire it up and have it connect to alarmpi on port 22 (which is the default SSH port), using the root username with root as the password.

When you are using the Bitvise client, by default a terminal console will be shown (after a successful connection) where you can type your commands. Let’s do first things first and change the default password by just typing passwd in the terminal console. The command line will now ask you to choose a new password and enter it twice, make sure you remember what you’ve typed of course.

The next important thing to do is to update your Arch Linux with all the latest patches and fixes. Just enter pacman -Suy in the command line, confirm with Y when prompted and watch the Raspberry Pi update itself. I have to admit while watching all the packages fly by, I started to feel as a real BOFH. 🙂

rasp_aspnet_update

Finally we are ready to install the Mono package, which can be done by typing pacman –S mono.

Step 3: Creating the Console Application skeleton

Now we are going to create a simple Console Application in C# which will use Owin to host ASP.NET. So fire up Visual Studio (remember we now have the free Visual Studio Community edition!), create a C# Console Application, and make sure to target .NET Framework 4.5.1. We’ll need to add the following NuGet packages:

  • Microsoft.Owin
  • Microsoft.Owin.Hosting
  • Microsoft.Owin.Host.HttpListener
  • Microsoft.Owin.Diagnostics (optional, I’ll explain further on why)

Next we need to add a new item to the project of the type OWIN Startup Class, and name it Startup.cs. For now, think of this class as the “web application” which we are going to host in our Console Application. Because we have added Microsoft.Owin.Diagnostics we can use the WelcomePageExtensions class to quickly have a simple test page ready. Just remove the comment from the generated code and replace it with the highlighted line below.

using System;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(OwinSample.Startup))]

namespace OwinSample
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseWelcomePage();
        }
    }
}

Notice the Startup class we just created, does not contain any information about port numbers, URL’s etc. This information is decoupled from the implementation and has to be specified in the Program class of the Console Application. So add the code below to the Main method of your Program class (which should already be in your project), and don’t forget to add the first using statement for the Microsoft.Owin.Hosting namespace.

using Microsoft.Owin.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OwinSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string baseUrl = "http://localhost:5000";
            using (WebApp.Start<Startup>(baseUrl))
            {
                Console.WriteLine("Press Enter to quit.");
                Console.ReadKey();

            }
        }
    }
}

This code basically instantiates our Startup class with the WebApp.Start method, using the URL http://localhost:5000. The Console.ReadKey() is there too prevent the Console Application to exit when the instantiation is done (which would kill the OWIN host as well of course). Now it’s time to hit F5 and start the project! The output of the Console Application will not be very exciting, but leave it running and use your favorite browser to navigate to http://localhost:5000. Your browser should render a Welcome page for any URL you type on the localhost:5000 site. This is because we didn’t specify a specific path in the app.UseWelcomePage line.

rasp_aspnet_test1

 

Step 4: Finishing the code

Before we will deploy the app to our Raspberry Pi, we’re going to improve the code a bit. First, let’s go back to the Startup class and modify the Configuration method with the snippet below.

app.UseWelcomePage(new Microsoft.Owin.Diagnostics.WelcomePageOptions()
{
    Path = new PathString("/welcome")
});

app.Run(context =>
{
    context.Response.ContentType = "text/plain";

    string output = string.Format(
        "I'm running on {0} nFrom assembly {1}", 
        Environment.OSVersion, 
        System.Reflection.Assembly.GetEntryAssembly().FullName
        );

    return context.Response.WriteAsync(output);

});

The first three lines will make sure the welcome page will only be displayed for the path /welcome (e.g. http://localhost:5000/welcome). The app.Run() is more interesting: this code adds a simple piece of so called middleware to the OWIN pipeline, implemented as a function that receives a Microsoft.Owin.IOwinContext instance. When the server receives an HTTP request, the OWIN pipeline invokes the middleware. The middleware sets the content type for the response and writes the response body. In the example above, for every request we are just building a simple string that displays the operating system version and the full name of the assembly that’s executing. You can start the Console Application again and check the output by navigation to any path, except /welcome of course (which will show the welcome page again).

Now, let’s switch back to the Program class and update the base URL as follows:

string baseUrl = "http://*:5000";

Notice I’ve replace the localhost with *, this means we are not only listing on the localhost hostname but on all hostnames assigned to your machine, including for example our machine’s IP address, machine name etc. There is only one caveat: if you’d like to run this code on Windows, your app needs to start with administrator privileges! So probably you want to close Visual Studio and start it again as admin. For just building the code, running as admin is of course not necessary.

Step 5: deploying to the Raspberry Pi

Finally we have some code which we’ll be able to test on the Raspberry Pi, so if you haven’t done already: build your project in Visual Studio. Once the assemblies are built, we can copy them to the Raspberry Pi. The Bitvise SSH client which I referred to in the beginning comes with a built-in SFTP client, which will allow us to very easily copy files around. You can start the SFTP client from the Bitvise SSH Client’s main window (check the icon in the vertical navigation on the left).

rasp_aspnet_sftpcopy

On the left side of the SFTP client you can navigate to the output of your project in Visual Studio, probably somewhere like DocumentsVisual Studio 2013ProjectsOwinSampleOwinSamplebinDebug. On the right hand side, the content of your Raspberry Pi’s SD card is shown. Navigate to / (type / in the drop down and hit enter) and create a new folder e.g. dotnet. Next, just drag-and-drop the files from the left side to the right side.

Step 6: running the app on the Raspberry Pi

And now the moment you’ve been waiting for: we are going to execute our code on the Raspberry Pi! Switch back to the terminal window (or open a new one if you’ve closed it), and navigate to the folder you create in the previous step (e.g. cd /dotnet, pay attention to the space after cd). Verify the files are there by typing the ls command.

rasp_aspnet_sshcd

Now we can start our .exe with the mono OwinSample.exe command. Pay attention to the fact Linux file names are case sensitive. Once the app is running, open your browser and navigate to the IP address or host name of your Raspberry Pi on port 5000 (e.g. http://alarmpi:5000). Check the result: your ASP.NET code is running on your Raspberry Pi!

rasp_aspnet_result

Conclusion and what’s next?

Pretty cool isn’t it? 🙂 In the next posts I’ll dive a bit deeper and extend to code to do some actual work (e.g. connecting to let’s say Azure, exposing an API, …). Another challenge to tackle is using the GPIOs of the Raspberry Pi in the .NET code so we can connect all kinds of sensors to it.

“It has never been a better time to be a software developer.”

  33 comments for “Running ASP.NET on a Raspberry Pi with Mono and OWIN

  1. November 21, 2014 at 8:07 pm

    I love your post.. Thanks!

    • Jan
      November 21, 2014 at 8:26 pm

      Thanks Bas!

  2. kris
    November 21, 2014 at 9:35 pm

    Nice article, looking forward to read about the rest of your experiments.
    Thanks for sharing.
    Kris.

  3. November 23, 2014 at 5:39 am

    What about debugging? Can I set RPi as debugging target within Visual Studio?

    • Jan
      November 23, 2014 at 9:09 am

      Good question! Never tried it … Of course you can debug while running on your dev box. But on the Pi it would be way cooler!

  4. November 24, 2014 at 1:56 pm

    https://pisharp.codeplex.com/

    Hi Jan,
    this could be a good starting point for the GPIO stuff 🙂
    now it’s time to figure out how to connect the Arduino Uno the the RPi.

  5. Harry
    December 1, 2014 at 11:12 pm

    Awesome article. I am going to buy a Raspberry Pi and give it a try soon. Thanks.

  6. James
    December 2, 2014 at 7:51 pm

    Hi,

    Just a noob comment here. I realize Arch Linux was your preferred distro on the Pi, and that’s ok, but would it be possible for you to show the steps under Raspbian as well? I think most folks use Raspbian. I’m probably ok on my end, and can figure things out, but I know a lot of folks come into the Pi with Raspbian, and move on to others, like Arch, later on (or never in my case).

    Thanks,

    • Jan
      December 4, 2014 at 8:23 am

      Thanks for the tip James. I’ll see if I can add instructions for Raspbian, it’s probably only different to install mono (pacman vs apt-get).

      • James
        December 4, 2014 at 10:05 pm

        The post was great btw, everything worked fine – even under Raspbian (I already had Mono set up). I’m really excited about ASP.Net on the Pi. It really opens up the Pi even more. I’d love to see this tied in with some of the other available Pi languages such as Python (wiringPi comes to mind). It would allow you to leverage a ton of existing working code out there written for the Pi.

        Thanks again!

      • Keith Wenzel
        December 9, 2014 at 5:15 pm

        It works well on Raspbian, too- the only change was to install mono with “sudo apt-get update && sudo apt-get install mono-complete”.

        This is cool. I haven’t played with OWIN much, and it’s kind of mind-blowing to see asp.net running on a pi….

        • Jan
          December 10, 2014 at 12:40 pm

          Thanks for confirming Keith! Indeed, it’s great to see the power of .NET & ASP.NET on such a device.

  7. Filipham
    December 2, 2014 at 8:49 pm

    Hi,

    Very nice post, unfortuneately was I lost at finding the “type” folder”.
    [ Navigate to / (type / in the drop down and hit enter) and create a new folder e.g. dotnet”]

    Can you specify the full path?

    And I also had to install mono, correct?

    • Jan
      December 4, 2014 at 8:35 am

      Hi Filipham, it’s just the root, so you need to type the / character in the right textbox and hit enter. Then right click anywhere in the list of folders/files to create a new folder called dotnet. Hope this helps!

  8. December 4, 2014 at 1:28 pm

    While this is cool, it you just wanted to quikcy host some web pages on the PI then you can’t beat apahce + PHP, literally :


    sudo apt get install apache2 php5

    then drop a php file in /var/www

    and you are done.

    • Jan
      December 4, 2014 at 2:30 pm

      Hi Coding Ninja, I agree with you if it’s just about hosting plain web pages (like in this article). But I wanted to be able to use the full power of the .NET framework and ASP.NET on the Raspberry Pi. Check my other posts for examples of that. 🙂

  9. Hossein
    January 2, 2015 at 3:37 am

    Thank you for your greate post, everything works fine 😀
    Is there any ways to serve .aspx (asp.net) files on raspberry pi?

  10. February 13, 2015 at 1:00 pm

    Jan,
    Cool.
    What about hosting this on nginx ?
    I know how to do this for a nodeJs app, but not for an owin based app.
    Cheers
    paul.

    • February 13, 2015 at 1:09 pm

      Haha, nginx is so cool.
      I got it working, it’s pretty similar to nodeJs.
      I’ll put in on my blog.
      paul.

  11. February 20, 2015 at 8:53 pm

    Jan,

    Thank you for this post, this gave my Raspberry Pi a new life. After a year in my closet it was time to remove the dust and do something useful with it.

    Regards,
    Elio

  12. joji thomas
    March 16, 2015 at 6:47 am

    hi jan,
    i am doing a project of object detection on raspberry pi.
    but the problem i am facing is that it give me an error’Presentation firmware’.
    my mono version is 3.2.7 but my program is targeted to 3.5.
    kindly help

  13. Sam Reach
    March 18, 2015 at 5:41 am

    I have tried this on Koding.com Ubuntu VM and getting the following exception. I have made sure the project is targeted to .net 4.5.1. Not sure whats happening. Any ideas?

    Missing method Where in assembly /home/samreach/OWINSample/Microsoft.Owin.Hosting.dll, type System.Linq.Enumerable

    Unhandled Exception:
    System.IO.FileNotFoundException: Could not load file or assembly ‘System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e08
    9’ or one of its dependencies.
    File name: ‘System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’
    at Microsoft.Owin.Hosting.Services.ServiceProvider.Add (System.Type serviceType, System.Type implementationType) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory+c__DisplayClass1.b__0 (System.Type service, System.Type implementation) [0x00000
    ] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory+c__DisplayClass4.b__3 (System.Type service, System.Type implementation) [0x0
    0000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.DoCallback (System.Action`2 callback) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.DoCallback (IDictionary`2 settings, System.Action`2 callback) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.Create (IDictionary`2 settings, System.Action`1 configuration) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.Create (IDictionary`2 settings) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.BuildServices (Microsoft.Owin.Hosting.StartOptions options) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.Start (Microsoft.Owin.Hosting.StartOptions options) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.Start[Startup] (Microsoft.Owin.Hosting.StartOptions options) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.Start[Startup] (System.String url) [0x00000] in :0
    at OwinSample.Program.Main (System.String[] args) [0x00000] in :0
    [ERROR] FATAL UNHANDLED EXCEPTION: System.IO.FileNotFoundException: Could not load file or assembly ‘System.Core, Version=4.0.0.0, Culture=neut
    ral, PublicKeyToken=b77a5c561934e089’ or one of its dependencies.
    File name: ‘System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’
    at Microsoft.Owin.Hosting.Services.ServiceProvider.Add (System.Type serviceType, System.Type implementationType) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory+c__DisplayClass1.b__0 (System.Type service, System.Type implementation) [0x00000
    ] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory+c__DisplayClass4.b__3 (System.Type service, System.Type implementation) [0x0
    0000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.DoCallback (System.Action`2 callback) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.DoCallback (IDictionary`2 settings, System.Action`2 callback) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.Create (IDictionary`2 settings, System.Action`1 configuration) [0x00000] in :0
    at Microsoft.Owin.Hosting.Services.ServicesFactory.Create (IDictionary`2 settings) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.BuildServices (Microsoft.Owin.Hosting.StartOptions options) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.Start (Microsoft.Owin.Hosting.StartOptions options) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.Start[Startup] (Microsoft.Owin.Hosting.StartOptions options) [0x00000] in :0
    at Microsoft.Owin.Hosting.WebApp.Start[Startup] (System.String url) [0x00000] in :0
    at OwinSample.Program.Main (System.String[] args) [0x00000] in :0

  14. Jim
    April 7, 2015 at 3:55 pm

    Great post! I think you forgot the “/’ in front of the “n” in the above code snippet.
    “I’m running on {0} nFrom assembly {1}”,

    Should be:
    “I’m running on {0} nFrom assembly {1}”,

  15. TJ
    August 4, 2015 at 4:04 pm

    This is absolutely brilliant! Thank you so much…

    A couple of quick questions:
    1) What do I need to do to have my owin self hosted web server start automatically on reboot?
    2) If I wanted to ever commercialize a small rasberry pi device with an owin server on it, what is my best option for burning an image on the pi with everything installed in one shot? I wouldn’t want to go through the thousand different steps to prepare every device. How would I create one image for the pi that ahs the latest OS, latest mono and latest binaries for my server AND any custom commands, for example to autostart the app?

    Thanks

  16. Jawand Singh
    October 16, 2015 at 7:46 pm

    can i use raspberry pi 2 running windows 10 IoT, as a web server for my intranet running asp.net ? please help me out 🙂

  17. May 20, 2016 at 10:47 am

    Weeeee, what a quick and easy sotiluon.

Leave a Reply

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