Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Running ASPNET 5 and .NET Core on Linux

0.00/5 (No votes)
11 Jan 2016 1  
I have been hearing quite a bit about the new ASPNET 5 (vNext) and .NET Core for a while now.

I have been hearing quite a bit about the new ASPNET 5 (vNext) and .NET Core for a while now. However, the frequent breaking changes between beta versions was too much for me to want to try it out. With ASPNET 5 and .NET Core in release candidate and a 1.0 release in sight, I thought it’s time to give it a try.

The super basics on ASPNET 5 and .NET Core

A one line summary on ASPNET 5 and .NET Core to set the stage.

ASP.NET 5 is a lean and composable framework for building web and cloud applications. ASP.NET 5 is fully open source

NET Core is a cross-platform implementation of .NET that is primarily being driven by ASP.NET 5 workloads, but also by the need and desire to have a modern runtime that is modular and whose features and libraries can be cherry picked based on the application’s needs.

Choosing the OS

ASPNET 5 and CoreCLR can run on Windows, Mac, or Linux. I choose try it on Linux as it’s the most interesting option to me. I think one can safely assume that ASPNET 5 will run relatively smooth on Windows compared to other OS options. Moreover, if I can get it to work on another OS, it should only work better in the windows environment.  Mac is interesting, but it’s use case is mostly as a development environment. Linux on the other can be both a viable development environment as well as an attractive hosting option.  In my test, I used Ubuntu Server 14.04 as it’s one of the most popular linux distributions and it’s easy to use.

Choosing between Mono Runtime vs .NET Core Runtime

Developers are going to have a lot more options in the new ecosystem. Even on Linux, there are two options for .NET runtime to choose from: mono runtime or coreclr. Mono is an open source implementation of .NET framework by Xamarin and has its own mono runtime. It has been around 10+ years and supports (some) web and desktop .NET applications to run on Linux. .NET Core is a a cross-platform implementation of  .NET by Microsoft and coreclrt is it’s runtime.

Picking between mono runtime and coreclr on linux is like picking between the full CLR and coreclr on windows. The full CLR supports any third party libraries available today. The coreclr while leaner and modular, requires libraries to specifically target the .NET Core. As a result, the amount of libraries supported in .NET Core will be limited in the beginning, but should improve over time as adoption increases.

One of the main goals of ASPNET 5 is about lightweight and composable framework, and I do think it’s worth pursuing. I am going to try out coreclr.

Setting up the environment

Getting the necessary components installed is surprisingly easy using the getting started page on asp.net site.

Install the .NET Version Manager (DNVM)

dnvm is the .NET Version Manager, a set of command line utilities to update and configure which .NET Runtime to use.

curl -sSL https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | DNX_BRANCH=dev sh && source ~/.dnx/dnvm/dnvm.sh

 

Install the .NET Execution Environment (DNX)

The .NET Execution Environment contains the code required to bootstrap and run an application. This includes things like the compilation system, SDK tools, and the native CLR hosts.

#install dnx prerequisite
sudo apt-get install libunwind8 gettext libssl-dev libcurl4-openssl-dev zlib1g libicu-dev uuid-dev

#use dnvm to install .net core
dnvm upgrade -r coreclr

At this point, if you run dnvm list to list the installed runtime, you should see something similar to:

Active Version              Runtime Architecture OperatingSystem Alias
------ -------              ------- ------------ --------------- -----
  *    1.0.0-rc1-update1    coreclr x64          linux           default

Notice only the coreclr runtime is installed. The getting started page on asp.net site also has instruction to install the mono runtime. Since I am interested in trying out the coreclr, not installing mono runtime will actually make it easier for me to verify it’s working in coreclr.

Install Libuv

Libuv is a multi-platform asynchronous IO library that is used by Kestrel, a cross-platform HTTP server for hosting ASP.NET 5 web applications.

sudo apt-get install make automake libtool curl
curl -sSL https://github.com/libuv/libuv/archive/v1.4.2.tar.gz | sudo tar zxfv - -C /usr/local/src
cd /usr/local/src/libuv-1.4.2
sudo sh autogen.sh
sudo ./configure
sudo make
sudo make install
sudo rm -rf /usr/local/src/libuv-1.4.2 && cd ~/
sudo ldconfig

Running the HelloMVC sample project

Once the environment is set, it’s also easy to run the Hello World MVC project.

#install git if it's not already installed
sudo apt-get install git

#clone the aspnet 5 repo
git clone https://github.com/aspnet/home

#change directory into the HelloMvc sample
#1.0.0-rc1-update matches the runtime version and could be different for you depends on what runtime you installed
cd home/samples/1.0.0-rc1-update1/HelloMvc/

#restore the packages required by HelloMvc project
dnu restore

#start the app
dnx web

If you browse to http://my-ip-address:5004, you should see the running sample application

HelloMvc

dnu restore command

dnu restore command looks at the dependencies of the application and download them, adding them to the apps packages directory. The dependencies is defined in project.json file. In the HelloMvc project, the dependencies are:

"dependencies": {
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final"
},

dnx web command

dnx web command runs the application.

In earlier documentation, you might see references to dnx kestrel command instead. If you try to run the dnx kestrel command. You will get this error message: Error: Unable to load application or execute command ‘kestrel’. Available commands: web.” The reason is that web  and kestrel are special commands expected to be defined in project.json. In the latest version of the HelloMvc sample, only web command is defined. In earlier beta version of the sample has both web and kestrel defined.

Open the latest version of the HelloMvc project.json file in 1.0.0-rc1-update1/HelloMvc directory,  here only the web command is defined. Also pay attention to the server.urls argument, the value is http://*:5004, this explains why the sample runs on port 5004.

commands: {
 web: Microsoft.AspNet.Server.Kestrel --server.urls http://*:5004
},

Open an earlier version of the HelloMvc project.json file in1.0.0-beta7/HelloMvc, you will see that both web and kestrel commands are defined.

commands: {
 web: Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5001,
 kestrel: Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5004
},

Running MusicStore sample project

Getting the HelloMvc sample to run was good, but I need to see a non trivial application running before I want to invest more time in this. My next test is getting the AspNet MusicStore sample project to run. This project has authentication and EF7, which makes it a good target. This project uses InMemory provider for database access as only SqlServer, SqlLite and InMemory providers are available at the moment.

Following similar steps we did for HelloMvc project

#clone the musicstore repo
git clone https://github.com/aspnet/MusicStore.git

#change the directory into the sample project
cd MusicStore/src/MusicStore

#restore package
dnu restore

#run the application
dnx web

At this point, I see the following in the console which indicated the application is running. It looks promising.

ubuntu@:~/MusicStore/src/MusicStore$ dnx web
Hosting environment: Production
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

However, if I  try to access it, it get the following scary looking exception.

fail: Microsoft.AspNet.Server.Kestrel[13]
An unhandled exception was thrown by the application.
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.CompilationAbstractions.ILibraryExporter' while attempting to activate 'Microsoft.AspNet.Mvc.Razor.Compilation.RoslynCompilationService'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.CreateCallSite(ServiceProvider provider, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetResolveCallSite(IService service, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetServiceCallSite(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.CreateCallSite(ServiceProvider provider, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetResolveCallSite(IService service, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetServiceCallSite(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.CreateCallSite(ServiceProvider provider, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetResolveCallSite(IService service, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetServiceCallSite(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.CreateCallSite(ServiceProvider provider, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetResolveCallSite(IService service, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetServiceCallSite(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType, ServiceProvider serviceProvider)
at System.Collections.Concurrent.ConcurrentDictionaryExtensions.GetOrAdd[TKey,TValue,TArg](ConcurrentDictionary`2 dictionary, TKey key, Func`3 valueFactory, TArg arg)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNet.Mvc.Razor.Internal.MvcRazorMvcViewOptionsSetup.ConfigureMvc(IServiceProvider serviceProvider, MvcViewOptions options)
at Microsoft.Extensions.OptionsModel.OptionsCache`1.CreateOptions()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at Microsoft.AspNet.Mvc.ViewEngines.CompositeViewEngine..ctor(IOptions`1 optionsAccessor)
at lambda_method(Closure , ServiceProvider )
at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNet.Mvc.ViewResult.<ExecuteResultAsync>d__26.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResultAsync>d__45.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResultFilterAsync>d__44.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAllResultFiltersAsync>d__43.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResourceFilterAsync>d__38.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAsync>d__33.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.<InvokeActionAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Session.SessionMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Session.SessionMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Diagnostics.StatusCodePagesMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Hosting.Internal.HostingApplication.<ProcessRequestAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.AspNet.Server.Kestrel.Http.Frame`1.<RequestProcessingAsync>d__3.MoveNext()

After some googling, the solution turned out to be a simple one. The sample requires the latest runtime. Run the following to update it to latest.

#upgrade the runtime to latest version
#-r specifies the runtime we are upgrading is coreclr
#-u use the unstable feed to get the latest
dnvm upgrade -u -r coreclr

#verify the version
dnvm list

#dnvm list output indicates that we have version 1.0.0-rc2-16319 and it's the active runtime
Active Version              Runtime Architecture OperatingSystem Alias

------ -------              ------- ------------ --------------- -----

       1.0.0-rc1-update1    coreclr x64          linux           

  *    1.0.0-rc2-16319      coreclr x64          linux           default

Run the dnx web command again and access the site. Yay! I am greeted with the home page of the music store. Browsing around the site and adding items to cart is also working.

MusicStore

Conclusion

In the blog post, we configured the .net runtime environment on linux. We also setup the HelloMvc and MusicStore sample application to run on the coreclr runtime. There were small hiccups but the overall experience is a pleasant one.

The libraries available on the Core CLR are still limited. But it looks like more are coming soon. A quick look at a couple libraries that I plan to use already has some support:

References:

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here