ASP.NET Core on my Raspberry Pi

Hi everyone, in order to have a website that is easy to develop and maintain, I recently decided to study and use the latest version of the ASP.NET framwork to use C# : ASP.NET Core.

Until now, I used a Raspberry Pi to host my websites, with Apache running on top of Raspbian.

I really like the new approach of ASP.NET Core with Kestrel, the new open-source web server. Your website resides in a single process listening on the specified endpoint. Then you install a reverse-proxy (like Apache or Nginx) in order to expose this local port to the internet. I think this is an easier and safer solution to website management than classic architectures like PHP.


The long road to the solution

My tests

To start, I tried to follow the quick startup guide on ASP.NET Core website. This tutorial shows how to get 'dotnet' tool to run on your platform then uses it to create a new project and finally to run it using kestrel.

Unfortunately, the dotnet tool is not supposed to be executed on ARM/Linux. As of now, you can't get and run .NET Core on ARM/Linux platform. When you create a new ASP.NET Core project, you have two options : use .NET Core, or use full .NET Framework. So I tried to build the website under Windows and to run it with Mono.


Install Mono 4.0.2

The default Mono version on Raspbian Jessie, Mono 3.2.8 does not support features used by Kestrel web server. To make things a bit harder, it's quite complex to build new versions of Mono with an ARMv6 CPU as hard floating point support is nearly mandatory. After some research, I found a prebuilt version of Mono 4.0.2 for Raspberry Pi. To install it, you can add the apt source below, then install Mono.

Please make sure that you have completely uninstalled any previous version of Mono before trying to install the new version, or you might end up with weird issues. In such cases, you will have to manually uninstall every mono packages.

  1. Add this repo to your apt sources :deb http://plugwash.raspbian.org/mono4 jessie-mono4 main
  2. Runapt-get update andapt-get install mono-complete

Replace Kestrel by a Linux/Mono compatible web Server

ASP.NET Core ships with 3 web servers :

  • Kestrel, the new open-source web server by Microsoft
  • IISIntegration, to plug your website in your existing IIS instance
  • WebListener, another web server using the WinRT API
Unfortunately, I did not manage to get Kestrel to work on my Raspberry Pi Model B. After several attemps to modify and rebuild Kestrel source code, all I got is an internal libUV error.

At this point, I decided to learn ho to interface another web server into ASP.NET Core. It would allow me to understand how it works from the inside, and open the way to other servers integration.

The API is quite undocumented for now, but I tried to disassemble WebListener to understand how it works. This implementation is fairly simple, as WebListener is just a wrapper around another existing web server.

Then I had to choose a Linux/Mono compatible web server. I considered using :

  • HttpListener: This web server is available in the .NET Framework by default, but it does require extra configuration on a Windows machine to allow a user to listener on a specified port.
  • uHttpSharp: Very interesting, but it uses LGPL licence. I tried to find a MIT one.
  • EmbedIO: My choice here.
I choosed EmbedIO because:

  • The API is super simple/clean to use
  • It is deeply integrated in .NET Framework, it uses HttpListenerRequest and HttpListenerResponse classes
  • It does not require any special configuration to work
  • It is open source with MIT licence
And finally the last step, I wrote the code to interface EmbedIO with ASP.NET Core logic. You can find the source code here : Microsoft.AspNetCore.Server.EmbedIO on GitHub

I packaged everything and pushed a NuGet Package available on NuGet here : Microsoft.AspNetCore.Server.EmbedIO on NuGet


Run ASP.NET Core project on Linux/Mono

After I got EmbedIO to work on Windows, I tried to run the server on Linux. Unfortunately, it did not work and the framework crashed at start, looking for ".NETFramework/v4.6/XXX.dll".

After some long investigation by disassembling Microsoft NuGet packages, I finally found the issue. The Microsoft.DependencyModel.dll NuGet package contains hard-codede references to Program files and Mono internal folders.

Unfortunately, the source code of this package is not available on GitHub. I tried to wrap the ReferenceCustomAssemblyResolver class into my own MonoCustomAssemblyResolver class that first tries to resolve assemblies from Mono framework folder.

This ugly fix worked, and I got to run ASP.NET Core sample website on my Raspberry Pi Model B on Linux/Mono. Even though this step is not the best solution, this one si available :


TL;DR Gimme the solution !

  1. Install Mono 4 (commands below are for Raspberry Pi)

sudo sh -c 'echo deb http://plugwash.raspbian.org/mono4 jessie-mono4 main > /etc/apt/sources.list.d/mono4.list'
sudo apt-get update
sudo apt-get install mono-complete

  1. Create a new ASP.NET Core with .NET Framework project in Visual Studio
  2. Add my two NuGet packages
  3. Change the startup code to use EmbedIO and activate Mono compatibility as shown below

IWebHostBuilder webHostBuilder = new WebHostBuilder()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseMonoCompatibility()
    .UseEmbedIO()
    .UseStartup<Startup>();

  1. Build the website
  2. Copy the project folder to your RPI, or any Linux/Mono powered device
  3. Run the website using mono

cd /path/to/project/root
mono bin/Debug/net46/win7-x64/MyWebSite.exe

  1. Have fun :)

Current limitations

The server takes ages to start

First, keep in mind that your Raspberry Pi is definitely slower than your desktop or laptop computer. ASP.NET Core framework takes several seconds to initialize, then each time your visit a page, it is rendered using Razor engine that is veeeeeery slow on Raspberry Pi.

One good thing is that a webpage is cached after the first visit, the the next accesses will be much faster, enough to use for your own website with multiple users.

If you use ASP.NET Core 1.1, you can precompile Razor views in an assembly you can publish with your website. The tool used to precompile views is open-source, but in its current version, only compatible with .NET Core (or I couldn't make it run with full .NET Framework).

Anyway, I forked Microsoft's repo to temporarily "fix" the full .NET Framwork compatibility. I will make a cleaner fix and I'll make a pull request later. You can find my fork here : https://github.com/jbatonnet/MvcPrecompilation

I don't have any numbers yet, but I can tell you that view precompilation speeds things up on a Raspberry Pi. Now only the first page takes time as Mono is initializing framework and is loading views.

EmbedIO features and performance

My implementation of EmbedIO support for ASP.NET Core is super simple for now. It clearly needs to be improved and new features need to be exposed and optimized. I hope that Kestrel will soon be fully compatible with Mono/Linux/RPI.

When I use EntityFramework Core with SQLite, I get internal fatal errors

The SQL queries logging is somehow broken with SQLite (and possibly other ?) using EntityFramework Core on Mono/Linux. As I found a workaround, I did not take much time to figure out a proper fix.

You can set logging level to "Warning" for "Microsoft" logs in appsettings.json. This setting will keep EF Core from showing each SQL query, and thus avoid the crash.



// Restons en contact

Si vous êtes intéressés par mon travail ou mes projets, vous pouvez me suivre et me contacter sur les réseaux suivants :

// Statistiques

Actualités
3
Articles
5
Projets
16