It’s an exciting time to be a developer. The tools available to us are getting better and more platform-agnostic and Microsoft is embracing the Open Source community. In this post, I am going to explore getting started with a ASP.NET Core app on Mac OS. I’m using Visual Studio Code as my editor but you can use whatever editor you prefer. Let’s get started!

First off, let’s create a directory and run dotnet new to create a new C# app. I’m calling my app HelloCore:

Deans-MacBook-Pro:Projects deandavidson$ mkdir HelloCore
Deans-MacBook-Pro:Projects deandavidson$ cd HelloCore/
Deans-MacBook-Pro:HelloCore deandavidson$ dotnet new
Created new C# project in /Users/deandavidson/Documents/Projects/HelloCore.

So, what just happened? Let’s take a look at project.json:

"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
"dependencies": {},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
"imports": "dnxcore50"

As you can see, by default it imports dnxcore50. Why? This allows us to reference pre-RC1 .NET Core Preview libraries. There is a lot of great info on Target Framework Monikers in this blog post. If you are unfamiliar with how .NET Core naming has changed, Hanselman does a really good job of explaining it here: ASP.NET 5 is dead - Introducing ASP.NET Core 1.0 and .NET Core 1.0 <- With a title like that, you basically don’t even need to READ the post.

In addition to project.json, we also have an entry point in to our application in Program.cs:

using System;

namespace ConsoleApplication
public class Program
public static void Main(string[] args)
Console.WriteLine("Hello World!");

Next, let’s restore dependencies using dotnet restore:

Deans-MacBook-Pro:HelloCore deandavidson$ dotnet restore
log : Restoring packages for /Users/deandavidson/Documents/Projects/HelloCore/project.json...
log : Lock file has not changed. Skipping lock file write. Path: /Users/deandavidson/Documents/Projects/HelloCore/project.lock.json
log : /Users/deandavidson/Documents/Projects/HelloCore/project.json
log : Restore completed in 939ms.
Deans-MacBook-Pro:HelloCore deandavidson$

And finally let’s run the app using dotnet run:

The App Runs!

It’s nice that our app runs but it doesn’t actually do anything. Let’s add the following dependencies to our project.json file’s root-level dependencies property which was previously blank:

  "dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0"

Do a dotnet restore to load in the new dependencies. For this app, I want to put my server-side code in a folder called Api and my client-side code in a folder called Client. So, first off: let’s create the Api folder and add a Startup.cs file with the following code:

using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;

namespace HelloCore.Api
public class Startup
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
// Add framework services.

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
// Set up our file server.
app.UseFileServer(new FileServerOptions()
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), @"Client")),
RequestPath = new PathString(""), // Our root path goes to the Client folder
EnableDirectoryBrowsing = false // Don't allow users to browse directories

Our app isn’t using this startup file yet or doing anything really. So, let’s change that by modifying our Program.cs file to configure and run our ASP.NET app:

using System.IO;
using Microsoft.AspNetCore.Hosting;
using HelloCore.Api;

namespace HelloCore
public class Program
public static void Main(string[] args)
var host = new WebHostBuilder()
.UseKestrel() // Since we are on Mac OS, we are using kestrel
.UseStartup<Startup>() // Use our Startup class in /App/
host.Run(); // Actually run the app

We can’t currently run the app because the Client folder doesn’t exist so our file server doesn’t work. Let’s create the Client folder and add Index.html to it with the following content:

<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello Core</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7"
<!-- Bootstrap Optional theme -->
<link rel="stylesheet" href="" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r"
<!-- Bootstrap JavaScript -->
<script src="" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
<!-- jquery -->
<script src="" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<!-- Our main app javascript -->
<script src="/Scripts/App.js"></script>
<div class="container">
<h1>Hello Core!</h1>
<button id="btn-get-contacts" class="btn btn-primary">Get Contacts</button>
<div id="contacts"></div>

Note that this file references /Scripts/App.js which doesn’t exist yet. Before we create our script, let’s create a route that it can call to get some contact data. Create a Controllers folder under /Api/ and add ContactsController.cs with the following self-deprecating code:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace HelloCore.Api.Controllers
public class ContactsController : Controller
// Note: for the sake of demo brevity we are just creating an
// inner class but don't do this in the real world.
public class ContactModel
// Nobody gets middle names around these parts...
public string FirstName { get; set; }
public string LastName { get; set; }

// GET api/contacts
public List<ContactModel> Get()
// Our data access layer, seen here, is the height of elegance.
return new List<ContactModel>() {
new ContactModel() { FirstName = "Dean", LastName = "Davidson" },
new ContactModel() { FirstName = "Scott", LastName = "Gu" },
new ContactModel() { FirstName = "Other", LastName = "Scott" },
new ContactModel() { FirstName = "John", LastName = "Doe" }

Now that we have a api/contacts route, we can add App.js to /Client/Scripts/ (create the Scripts folder):

$(document).ready(function() { 
// When the user clicks the "get contacts" button, retrieve contacts from our web API and display them.
$('#btn-get-contacts').click(function() {
$.get('/api/contacts', function(data) {
// Note: don't really do this either. Use a templating engine or SPA framework
$('#contacts').html('<ul id="contacts-group" class="list-group"></ul>');
var contactsGroup = $('#contacts-group');
for (var i = 0; i < data.length; i++) {
contactsGroup.append('<li class="list-group-item"><span class="glyphicon glyphicon-user"></span> ' + data[i].firstName + ' ' + data[i].lastName + '</li>');

Now, if we do a dotnet run and navigate to http://localhost:5000/, we should be able to press our button and get data back from our API:

Core App Running In Chrome


This is a very basic example but it will familiarize you with the building blocks of an ASP.NET Core web app. You can download/fork the source for this post here. As usual, let me know if you have any questions and I will be happy to help.