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.
- ASP.NET 5 and AngularJS Part 1, Grunt, Uglify, and AngularJS
- ASP.NET 5 and AngularJS Part 2, Using the MVC 6 Web API
- ASP.NET 5 and AngularJS Part 3, Adding Client Routing
- ASP.NET 5 and AngularJS Part 4, Using Entity Framework 7
- ASP.NET 5 and AngularJS Part 5, Form Validation
- ASP.NET 5 and AngularJS Part 6, Security
- ASP.NET 5 and AngularJS Part 7, Running on a Mac
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.
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
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
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.
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
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.
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:
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:
-
Hit CTRL-Z to stop Kestrel.
-
Type ps to get a list of processes.
-
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
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.
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.