ASP.NET 5 and AngularJS Part 7, Running on a Mac

This is the seventh part in a multiple part blog series on building ASP.NET 5 (ASP.NET vNext) apps with AngularJS. In this series of blog posts, I show how you can create a simple Movie app using ASP.NET 5, MVC 6, and AngularJS.

You can download the code discussed in this blog post from GitHub:

https://github.com/StephenWalther/MovieAngularJSApp

In this blog post, I walk through the steps required to run an ASP.NET 5 app on a Mac. In particular, I setup the Movies app to run on OSX Yosemite on my MacBook Pro. I try to follow the instructions for running ASP.NET 5 on OSX created by the ASP.NET team as closely as possible but I encounter some issues along the way:

https://github.com/aspnet/home

Installing Mono

Before you can run ASP.NET 5 on a Mac, you must first install Mono. The Mono Project is independent from Microsoft. Mono is an open-source implementation of .NET for different platforms such as Mac OSX and Linux.

In theory, the Homebrew script supplied by the ASP.NET team should install the correct version of Mono automatically, but I couldn’t get this to work. I ended up installing Mono myself by visiting the following page:

http://www.mono-project.com/download/

Installing Mono was painless. They have a nice installer that does all of the work.

Install Mono

Updating Homebrew

The next step is to use Homebrew to install KVM. I ran into several problems getting this to work on OSX Yosemite.

The first problem is that the location of Ruby on Yosemite has changed which breaks Homebrew:

http://apple.stackexchange.com/questions/153790/how-to-fix-brew-after-its-upgrade-to-yosemite

I executed the following sequence of commands to update Homebrew so it works with OSX Yosemite:

cd /System/Library/Frameworks/Ruby.framework/Versions 
sudo ln -s Current 1.8 
sudo brew update 
sudo rm 1.8

Installing KVM

After I got Homebrew into a working state, I used Homebrew to install the ASP.NET 5 KVM. First, you need to execute the following command to associate the aspnet/k GitHub repository with Homebrew:

brew tap aspnet/k

Tap ASPNET

Next, run the following command to perform the actual install of kvm:

brew install kvm

After running this command, I ran into an error stating that kvm was installed but “just not linked”. Executing the following command fixed the problem:

sudo brew link kvm

Leave and re-enter Terminal and execute the following command to verify the installation of kvm and Mono:

kvm list

KVM List

Before running the kvm or k command, you need to run the following command first:

source kvm.sh

You’ll need to run this command once each and every time you open the Terminal app so Terminal knows where to look for kvm and k.

Installing the Movies App

Next, I grabbed the source code for the Movies app from my GitHub repository by executing the following command:

git clone https://github.com/StephenWalther/MovieAngularJSApp.git

The modified Movies app described in this blog post can be found in the Part7 folder.

I used Sublime Text to edit the files in the Movies app while running OSX.

Sublime Text

Using the In-Memory Database

In previous parts of this blog series, I used Entity Framework 7 with Microsoft SQL Server to store my list of movies. This won’t work on a Mac because you cannot run Microsoft SQL Server on a Mac.

You have a few choices here:

  • SQLite – SQLite is an open-source database that works on Windows, Windows Phone, OSX, and Linux. According to the description page (http://www.sqlite.org), it is the most widely deployed database in the world.

  • Azure SQL Database – Connect to a Microsoft Azure SQL Database from your app running in OSX. In other words, host the Movies app on OSX and your database in the cloud.

  • In-Memory – Use the In-Memory provider for the Entity Framework to run an in-memory database (which dies and goes away each time you restart your web server).

I could not get SQLite to work with the current BETA version of ASP.NET 5. I could not find the UseSQLite() method, so I assume that this provider is not ready yet. You can look at the SQLite repository here:

https://github.com/aspnet/DataCommon.SQLite

Using an Azure SQL Database would be the best choice for a real-world application. However, I did not want to require an external dependency to run the Movies app.

Therefore, I decided to use the In-Memory provider for the Entity Framework. The disadvantage of the In-Memory provider is that the database does not persist. However, the advantage is that it works across Windows, OSX, and Linux.

I had to make two changes to the Movies app to use the In-Memory provider. First, I had to add a reference to EntityFramework.InMemory to the dependencies section of the Movies app project.json file. Adding this dependency pulls in the NuGet package for the In-Memory provider.

Second, I had to make two changes to the Startup class. I updated the ConfigureServices() method in Startup.cs to check whether the app was running on Mono (OSX or Linux). When the Movies app is run on Mono, it uses the In-Memory provider. Otherwise, when the Movies app is run on Windows, it uses Microsoft SQL Server.

public void ConfigureServices(IServiceCollection services)
{

	//Sql client not available on mono
    var usingMono = Type.GetType("Mono.Runtime") != null;

    // Add EF services to the services container
    if (usingMono)
    {
        services.AddEntityFramework(Configuration)
                .AddInMemoryStore()
                .AddDbContext<MoviesAppContext>();
    } else {
		services.AddEntityFramework(Configuration)
				.AddSqlServer()
				.AddDbContext<MoviesAppContext>(options =>
				{
					options.UseSqlServer(Configuration.Get("Data:DefaultConnection:ConnectionString"));
				});
	}

	// add ASP.NET Identity
	services.AddIdentity<ApplicationUser, IdentityRole>(Configuration)
		.AddEntityFrameworkStores<MoviesAppContext>();

	// add ASP.NET MVC
	services.AddMvc();
}

I also updated the CreateSampleData() method in the Startup class. The Startup class calls EnsureCreatedAsync() to create the database only when you are running the app on Windows and not Mono. You don’t need to create an actual database file when using the In-Memory provider.

private static async Task CreateSampleData(IServiceProvider applicationServices)
{
	using (var dbContext = applicationServices.GetService<MoviesAppContext>())
	{
		// ensure SQL Server database created
		var sqlServerDatabase = dbContext.Database as SqlServerDatabase;
		if (sqlServerDatabase != null)
		{
			sqlServerDatabase.EnsureCreatedAsync().Wait();
		}

		// add some movies
		var movies = new List<Movie>
		{
			new Movie {Title="Star Wars", Director="Lucas"},
			new Movie {Title="King Kong", Director="Jackson"},
			new Movie {Title="Memento", Director="Nolan"}
		};
		movies.ForEach(m => dbContext.Movies.AddAsync(m));

		// add some users
		var userManager = applicationServices.GetService<UserManager<ApplicationUser>>();

		// add editor user
		var stephen = new ApplicationUser
		{
			UserName = "Stephen"
		};
		var result = await userManager.CreateAsync(stephen, "[email protected]");
		await userManager.AddClaimAsync(stephen, new Claim("CanEdit", "true"));

		// add normal user
		var bob = new ApplicationUser
		{
			UserName = "Bob"
		};
		await userManager.CreateAsync(bob, "[email protected]");
	}
}

Using Kestrel

You can’t use Internet Information Services (IIS) on OSX. Instead, you need to use the Kestrel web server, which was built by the ASP.NET team to work with both OSX and Linux.

Under the covers, Kestrel is built on top of Libuv, which is also used by NodeJS. You can read about Libuv here:

http://nikhilm.github.io/uvbook/

In order to use Kestrel, you must add a dependency on Kestrel to your project.json file. Here’s what my complete dependencies section looks like (the top 2 dependencies are used by OSX):

"dependencies": {
     "Kestrel": "1.0.0-*",
     "EntityFramework.InMemory": "7.0.0-*", 

     "EntityFramework.SqlServer": "7.0.0-beta2",
     "EntityFramework.Commands": "7.0.0-beta2",
     "Microsoft.AspNet.Mvc": "6.0.0-beta2",
     /* "Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-beta2", */
     "Microsoft.AspNet.Diagnostics": "1.0.0-beta2",
     "Microsoft.AspNet.Diagnostics.Entity": "7.0.0-beta2",
     "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta2",
     "Microsoft.AspNet.Security.Cookies": "1.0.0-beta2",
     "Microsoft.AspNet.Server.IIS": "1.0.0-beta2",
     "Microsoft.AspNet.Server.WebListener": "1.0.0-beta2",
     "Microsoft.AspNet.StaticFiles": "1.0.0-beta2",
     "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta2",
     "Microsoft.Framework.CodeGenerators.Mvc": "1.0.0-beta2",
     "Microsoft.Framework.Logging": "1.0.0-beta2",
     "Microsoft.Framework.Logging.Console": "1.0.0-beta2",
     "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta1"
  },  

By the way, a Kestrel is a type of bird (a falcon) that has the special ability of being able to fly in dead air.

Fetching NuGet Dependencies

Before we can run our Movies app, we need to pull in all of the NuGet dependencies that we listed in the project.json file. Execute the following command:

 
kpm restore

KPM Restore

Running Kestrel

We are finally ready to run the Movies app on OSX. Execute the following command:

k kestrel

Executing this command will startup the Kestrel web server.

Start Kestrel

By default Kestrel runs on port 5104. You can determine the port being used by Kestrel by taking a look at the commands section of your project.json file.

Open a browser and navigate to the following address and you should see the Movies app:

http://localhost:5104

Movies App

The Movies app is completely functional. You can login using either the Stephen and Bob user (with the password [email protected]). If you login as Stephen then you can add, edit, and delete movies.

Because we are using the In-Memory provider, any changes that we make will disappear when we stop the app. If you want to persist changes then you should use an Azure SQL Database and persist your data to the cloud.

Stopping Kestrel

Stopping Kestrel is surprisingly difficult. On OSX, hitting CTRL-C in Terminal won’t do anything and won’t stop the server. Here are the steps that work for me:

  1. Hit CTRL-Z to stop Kestrel.

  2. Type ps to get a list of processes.

  3. Type kill followed by the process id to kill the Mono process.

There is a StackOverflow description of this issue here:

http://stackoverflow.com/questions/25712814/how-to-quit-asp-net-kestrel-web-server-on-a-mac

Kill Kestrel

Summary

The goal of this blog post was to describe the set of steps that I needed to complete to get the Movies app running on OSX. There were some bumps on the way, but it is amazing to see ASP.NET (and the Entity Framework) running outside of Windows.

Discussion

  1. Shayne Boyer says:

    Great series, check out the Kulture addin and OmniSharp and you can run the kpm and other ASP.NET 5 commands right from the Sublime UI.

  1. […] ASP.NET 5 and AngularJS Part 7, Running on a Mac – Stephen Walther […]