ASP.Net 5 Linux support for runtime JS & CSS preprocessing with Smidge
I’ve been working on a side project called Smidge which is a runtime JS & CSS preprocessor for ASP.Net 5. I started this late last year after the 2014 MS MVP Summit as a good starting point to deep dive into ASP.Net 5. I’ve been keeping the codebase up-to-date with the beta releases of ASP.Net 5, I have it cross compiled to both dnx451 and dnxcore50 and recently updated to use Beta 7. This week I decided to give running ASP.Net 5 CoreCLR on Linux… and the result is IT WORKS!
I have next to no experience with Linux and considering that, it wasn’t actually very difficult to get my test site for Smidge up and running. Here’s the info on how I set this up:
Linux setup
I decided to use Ubuntu 14.04.3 LTS. I installed in on Hyper-V on Windows 10 and that was all very easy. I also setup SSH with the server so that I could remote terminal to it which is much nicer than using the terminal through the UI interface of Ubuntu via Hyper-V. Then basically followed the instructions here: https://github.com/aspnet/Home/blob/dev/GettingStartedDeb.md#getting-started-with-aspnet-5-and-linux – except that I didn’t configure any Nuget package sources since that is built into dnvm now. Once that was done I used dnvm to install the default runtime: dnvm upgrade. This installed mono by default but for my purposes I needed ASP.Net 5 CoreCLR since that’s what Smidge is built against and I wanted to see this CoreCLR cross-platform stuff in action. Issuing this command does the trick: dnvm install 1.0.0-beta7 -r coreclr . Now when I list the runtimes installed (dnvm list) I get:
So now dnx is installed! We’re ready to go.
dnu publish & bash
What I really wanted to see was that I could build my solution on my Windows machine in Visual Studio and then export it and see if it would work on the Linux machine. Through the command line on Windows at the root of my project I used dnu publish (https://github.com/aspnet/Home/wiki/DNX-utility#publish-dnu-publish) which outputs a ‘self-contained directory that can be launched’ = great! So I executed that command, it put the folder in my /bin folder for my current project and I copied over that directory to my Linux machine…. and realized I didn’t know what to do next ;)
I had a look through the files that dnu publish exports and the one that is listed in ASP.Net’s docs is the output/kestrel.cmd (since the command in my project is named ‘kestrel’). Inside this file this is listed:
@"dnx.exe" --appbase "%~dp0approot\src\Smidge.Web" Microsoft.Dnx.ApplicationHost --configuration Debug kestrel %*
which if you want to translate to Linux, you could execute this at the Linux terminal at the root of this folder:
dnx --appbase "approot/src/Smidge.Web" Microsoft.Dnx.ApplicationHost --configuration Debug kestrel
… which will actually work, BUT it turns out there’s a way more Linuxy way to do it. dnu publish also creates this file which isn’t in the docs: output/kestrel Having a look at this file, the first line is: #!/usr/bin/env bash … so I can only assume this is something for Linux since I’ve heard the term bash before. Turns out on Linux you can just do this in the terminal from the root of this folder!
bash kestrel
Result:
WHOOHOOO!
Lets see it in action
Now that it’s running, I’ll jump over to the UI in Ubuntu and fire up the browser… Tada!!
Problems along the way
I probably made the above sound a bit easier than it was ;) … I did run into a few setup issues along the way.
Problem #1
The first one was when I first tried to run dnx:
failed to locate libcoreclr with error libunwind.so.8: cannot open shared object file: No such file or directory” when you run dnx or dnu command
I solved this issue from reading about it on this nice post: http://blogs.msdn.com/b/rdcdev/archive/2015/08/28/some-issues-when-hosting-asp-net-5-on-ubuntu-on-azure.aspx which has some other nice tricks if you run into Ubuntu issues with ASP.Net 5. The solution was that I needed to run this command:
sudo apt-get install libunwind8
Problem #2
Then I got this exception:
The type initializer for 'libcrypto' threw an exception
Which is referenced on this ASP.Net issue: https://github.com/aspnet/dnx/issues/1806 … and turns out that it’s also referenced on the above link. I can’t remember where exactly I found this solution but I had to run:
apt-get install libcurl4-openssl-dev
Problem #3
After fixing those 2 things, the bash kestrel command succeeded but when I went to test this in my browser, I just had a white screen. After Googling, I found this link: http://stackoverflow.com/questions/28845892/blank-white-screen-on-error-with-kestrel-asp-net-5 and as it turns out, I had the same issue. I forgot to add the error handling middleware. Perhaps when running in VS with IIS this is automatically taken care of for you… not sure. But in any case, it’s super important that you add it and you should add it as the first middleware so you can actually see if your other middleware fails, typically your ‘Configure’ method in your Startup class should start with:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // Add the following to the request pipeline only in development environment. if (env.IsDevelopment()) { app.UseErrorPage(); } else { // Add Error handling middleware which catches all application specific errors and // sends the request to the following path or controller action. app.UseErrorHandler("/Home/Error"); }
Problem #4
We’re not in Windows-land anymore! The errors I was getting were due to invalid file system paths. Turns out that .Net has always had this property: System.IO.Path.DirectorySeparatorChar but there wasn’t much reason to use it since .Net only runs in Windows and that character is always backslash. So I had to change my hard coded backslash use to use this instead. Next file path issue was case sensitivity… DOH. The Smidge configuration file is: ~/smidge.json however in my c# code I was trying to load it in with “Smidge.json” which fails in Linux of course.
Problem #5
Static files… I’m so used to working with IIS I forgot that outside of IIS I’d need to make sure the static file middleware was used:
app.UseStaticFiles();
I fixed that up and everything just worked… very freakin cool!!
Release – beta6
I’ve put up a new release on Nuget with these changes:
PM> Install-Package Smidge -Pre
And the source is on GitHub:
- beta6 release: https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-beta6
- home & docs: https://github.com/Shazwazza/Smidge