GeoGems: An ASP.Net Core App on Linux

GeoGems

Articles in This Series

GeoGems Part 1: Getting Set Up

The Idea

I’m starting a new “practice project” to suss out creating a complex .Net application on Linux. The application is going to be called GeoGems.io. I’m a runner, but now that I’m older and have a child and slower etc…I don’t really run to be fast anymore.  I just run because I love to run. But I love to trail run and run on routes I’ve never encountered before. A lot of times I’ll come across awesome urban art or other really cool landmarks.  I was thinking how cool it would be to have a running app that showed you cool things that others had tagged that you were near…so you could change course and go check things out as you run. And also allow you as a runner to share things you’ve found. So the basic idea is that you can use an app to stop and take pictures and “GeoCode” and tag sites as you run or walk. I’d also like to track some basic running stats like distance and pace. Kind of a combination of a running app and a geocaching app, but based on landmarks as the things to find.

My Technology Stack

The goal is to use free/opensource in all possible cases to keep this zero cost. I want to create this app with C# running ASP.Net Core on Linux. I want to use Docker as my deployment approach.  I’m thinking about Aurelia for the admin front end and Ionic 2 for the mobile web/web app. If Aurelia releases their Aurelia Interface product any time soon I might swap that for Ionic. I’ll probably want some kind of event sourcing backend for recording route events so I’m probably going to try Marten, since that sits on Postgres and also has a document store capability (and then the underlying relational DB if I need it). Hopefully they release the event store support soon.

Code Tools

I’m planning on coding this on Linux (Ubuntu) as well, so I’ll be using Visual Studio Code with OmniSharp. I’ll also use Code as my JavaScript editor for client apps.

Deployment

I want to deploy to the cloud, so I’m thinking DigitalOcean (although AWS does have their free plan). You just get so much bang for your buck with DigitalOcean.

Why This Approach

There are several.  The first is that I’ve been a Windows/Mac user my entire life, including my entire coding life and always wanted to explore Linux in more detail. And the move for .Net Core to support Linux is compelling for several reasons:

  • Because it’s there…why not give it a shot?
  • Cost – Price out some Windows VM’s on Azure vs Linux VMs.  The Linux VMs come in at 60% of the cost.  That’s huge for a startup or even ambitious hobby projects.
  • Platforms/Hosts – Using Linux opens up several awesome and inexpensive hosts like Digital Ocean.  It also opens up some great DevOps/Depoyment tools like Docker. I know Windows containers are on the horizon…but they are definitely behind the curve and they still need to run on Windows (see Cost).
  • .Net and C# are awesome – I’ve used various Node frameworks and they are impressive…but there’s something to be said about the sweet spot that C# hits as a strongly typed language with so many features, like:
    • Lambdas/LINQ/Delegates
    • Async/Await
    • Great Generics support
    • Dynamics
    • Immutables
    • I could go on for a while here…it’s a fantastic language…and C# 7 looks to be even better.
  • .Net has a solid and growing open source community…and now even .Net Core is open source…so long Ballmer…
  • .Net Core Performance on Kestrel is impressive…even for the RC, so you’re getting a lot of bang for your compute buck.  This great performance means smaller/fewer servers in your farm.

So why not just develop on Windows using Visual Studio 2015 (which I have available) and target the core framework so that you can run on Linux?  There are a couple of reasons.  The first is that, as mentioned above, I want to improve my comfort with Linux as well as get a better grasp of using a “minimal toolset” approach.  The other is ease of integration with Docker. Docker can be set up on Windows (currently by using VirtualBox)…but it’s really just a mini Linux VM…why not just get on Linux instead where it’s a first class citizen?

That’s all for now…I’ll use this as a landing page for upcoming posts.

Nozus Step 3: Adding ASP.Net Identity to MVC 6

In the previous post, we added some simple logging to our API using Serilog and simple middleware. In this installment, we’ll be adding identity management to that project using the standard ASP.Net Identity libraries.

First, let’s do a little project cleanup.  In Nozus.Data and Nozus.Domain, go ahead and delete the default Class1 that was added when we created those projects. Also, from the HomeController in Web.Api, make sure you removed the thrown exception added at the end of the previous post.

Now we’re going to add in packages needed for the identity system. Open your Package Manager Console (Tools –> Nuget Package Manager –> Package Manager Console).  In the console select your VNext package source and install the Identity.EntityFramework package into both the Data and Web.Api projects.  Make sure to includeprerelease which can be abbreviated to “-inc”.

PM> Install-Package Microsoft.AspNet.Identity.EntityFramework -inc
Installing NuGet package Microsoft.AspNet.Identity.EntityFramework.3.0.0-beta3.
PM> Install-Package Microsoft.AspNet.Identity.EntityFramework -inc
Installing NuGet package Microsoft.AspNet.Identity.EntityFramework.3.0.0-beta3.

We’re going to be using SQL Server as the data store, but you can use any applicable store.  From the Package Manager Console, install EntityFramework.SqlServer into the Web.Api project only.

PM> Install-Package EntityFramework.SqlServer -inc
Installing NuGet package EntityFramework.SqlServer.7.0.0-beta3.

Finally, in our Domain project, we’re going to add in a package to support basic Authentication classes.  We’ll derive from these later.

PM> Install-Package Microsoft.AspNet.Identity.Authentication -inc
Installing NuGet package Microsoft.AspNet.Identity.Authentication.3.0.0-alpha4.

Now that all packages are installed…let’s put identity into place.  We’re going to first add in our user and role classes into the Domain project.  In the Domain project, add an Entities folder and inside of that folder add an Identity folder. Inside of the Identity folder, add two classes, AppUser and AppRole.  For the moment, these classes require no implementation other than inheriting from the proper identity classes.  AppUser will inherit from IdentityUser<int> and AppRole will inherit from IdentityRole<int>.  The type specifies the type of the ID that will be used in the entities and the database.  By default, an int will be set up as an Identity column in SQL Server.

using Microsoft.AspNet.Identity;
namespace Nozus.Domain.Entities.Identity
{
    public class AppUser : IdentityUser<int>
    {}
}

using Microsoft.AspNet.Identity;
namespace Nozus.Domain.Entities.Identity
{
   public class AppRole : IdentityRole<int>
   {}
}

Now add a reference to the Domain project from the Data project.  Add a reference to both Domain and Data from the Web.Api.  In the Data project, add an AppDbContext class.  Inherit this class from IdentityDbContext<AppUser, AppRole, int>.


using Microsoft.AspNet.Identity.EntityFramework;
using Nozus.Domain.Entities.Identity;
namespace Nozus.Data
{
    public class AppDbContext 
        : IdentityDbContext<AppUser,AppRole,int>;
    {}
}

IdentityClassesWe’ll use this as our EF dbContext for the solution, and we can dual purpose it by inheriting from the IdentityDbContext.  We’re also specifying our User and Role types as well as the type for the IDs, which applies to both User and Role.  The project structure should now look similar to the image at the right.

Now lets fix up our Web.Api project to use this identity setup.  All the initial action here is going to be in the Startup class because, as expected, the identity functionality is set up using middleware.  In the ConfigureServices method, we’ll configure both Entity Framework and Identity as follows:


public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(Configuration);

// Add EF services to the services container.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<AppDbContext>();

// Add Identity services to the services container.
services.AddIdentity<AppUser, AppRole>(Configuration)
.AddEntityFrameworkStores<AppDbContext, int>();

services.AddMvc();
services.Configure<MvcOptions>(options =>
{
  options.OutputFormatters.RemoveAll(formatter => 
  formatter.Instance is XmlDataContractSerializerOutputFormatter);
});
}

You can  see that we’re adding EF, telling it to use SQL Server and then giving it the type of our DbContext.  Next we’re adding identity, telling it our user and role types, and letting it know to use an EF store with our DbContext and the type of IDs it will be using.  Next, we’ll do some more setup in the Configure method.


public void Configure(IApplicationBuilder app, 
  IHostingEnvironment env, ILoggerFactory loggerfactory)
{
  loggerfactory.AddSerilog(GetLoggerConfiguration());
  app.UseStaticFiles();

  //*** Tell the app to use Identity ***//
  app.UseIdentity();

  app.UseMiddleware<ErrorLoggingMiddleware>();
  app.UseMvc(routes =>
  {
    routes.MapRoute(
    name: "default",
    template: "{controller}/{action}/{id?}";,
    defaults: new { 
        controller = "Home", 
        action = "Index" });
  });

  //***  Initialize the DB ***//
  if(env.EnvironmentName == "Development")
    InitializeDb(app.ApplicationServices).Wait();
}

private static async Task InitializeDb(
  IServiceProvider applicationServices)
{
  using (var dbContext = 
    applicationServices.GetService<AppDbContext>())
  {
    var sqlServerDatabase = 
      (SqlServerDatabase)dbContext.Database;
    await sqlServerDatabase.EnsureDeletedAsync();
    if (await sqlServerDatabase.EnsureCreatedAsync())
    {
      //We could add some test data...perhaps later
    }
  }
}

Here, we’re telling the app to use identity.  We’re also calling our InitializeDb method to drop and recreate our database. This is mainly in place for dev purposes, so you could call alternate database setups depending on whether you were running integration tests/developing/etc…  We’ll just have an empty database to start with for now.  We’re using the built in env.EnvironmentName to test that this is running in Dev before dropping and recreating our database.

When you installed the EF packaged into the Web.Api project, it should have automatically added a config section to your config.json file.  Take a look, it should look similar to the following:

{
 "Data": {
   "DefaultConnection": {
   "ConnectionString": 
    "Server=localhost;Database=Nozus;Trusted_Connection=True;
     MultipleActiveResultSets=true"
   }
 },
   "EntityFramework": {
     "AppDbContext": {
     "ConnectionString": "Data:DefaultConnection:ConnectionString"
     }
   }
}

The data section should contain a connection string.  By default it will set up a connection string to localDB with a random database name.  I’ve changed it to point to my local Sql Server Dev Edition, but localDB will work just fine.  You can explicitly set up which connection string EF uses, but by default, it’s going to find the entry under the EntityFramework section that matches the name of the DbContext.  So in this case, make sure that it’s named “AppDbContext”.

When exchanging data with our API, it’s important that we define contracts for data going in and out. We don’t want to use the domain classes, as they will have lots of properties that we don’t want to expose to the outside world.  If there isn’t already a Models folder in your Web.Api project, add one.  In this folder, create a new class called UserModel.  It should look like the following:

using System.ComponentModel.DataAnnotations;
namespace Nozus.Web.Api.Models
{
public class UserModel
{
   public int? Id { get; set; }
  [Required]
  [Display(Name = "User name")]
  public string UserName { get; set; }

  [Required]
  [StringLength(100, 
  ErrorMessage = 
    "The {0} must be at least {2} characters long.", 
  MinimumLength = 6)]
  [DataType(DataType.Password)]
  [Display(Name = "Password")]
  public string Password { get; set; }

  [DataType(DataType.Password)]
  [Display(Name = "Confirm password")]
  [Compare("Password",
  ErrorMessage = 
    "The password and confirmation password do not match.")]
  public string ConfirmPassword { get; set; }
}
}

So now that we’ve got a model class, how to we map from our Domain AppUser class to this UserModel class. You can roll your own mappers, which is fine, but you might want to use a mapping library.  In .Net almost everybody uses AutoMapper. It is very versatile and works in a variety of environments.  So feel free to use AutoMapper if you like, but I’m going to use Mapster instead. It’s another mapper that I currently support.  I use it because it gives me everything I need from AutoMapper and is ~10-50x faster on average. The setup of these two mappers is very similar, so they translate easily in most cases.  Install the Mapster package into your Web.Api project, selecting nuget.org as your source.

PM> Install-Package Mapster
Installing NuGet package Mapster.1.14.0.

Now create a Mapping folder in your Web.Api project.  Create a class in this folder called UserMapping.  It should inherit from Mapster’s Registry class. A registry class can be scanned at startup to register all of the mappings.

using Mapster;
using Mapster.Registration;
using Nozus.Domain.Entities.Identity;
using Nozus.Web.Api.Models;
namespace Nozus.Web.Api.Mapping
{
public class UserMapping : Registry
{
   public override void Apply()
  {
    TypeAdapterConfig<AppUser, UserModel>.NewConfig()
    .Ignore(dest => dest.ConfirmPassword)
    .Ignore(dest => dest.Password);
  }
}
}

Here, we’re telling Mapster to map AppUser to UserModel and to ignore the destination ConfirmPassword and Password fields since we don’t want those returned.  Now in the Startup.cs constructor, we’ll add a call to find and register all of our Registry classes.  Of course right now there’s just the one, but it will grow as the application grows.

public Startup(IHostingEnvironment env)
{
  Configuration = new Configuration()
  .AddJsonFile("config.json")
  .AddEnvironmentVariables();
  //Scan for our mappings
  Mapster.Registration.Registrar
  .RegisterFromAssembly(Assembly.GetExecutingAssembly());
}

So now to finish up we’ll implement our AccountController. This will do things like register new users, reset passwords, inactivate users etc…  For right now we’ll just add methods to add a new users and to retrieve a user.  Add the below code to your AccountController class.

using System.Net;
using System.Threading.Tasks;
using Mapster;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;
using Nozus.Domain.Entities.Identity;
using Nozus.Web.Api.Models;

namespace Nozus.Web.Api.Controllers
{
  [Route("[controller]")]
  public class AccountController : Controller
  {
   private readonly UserManager<AppUser> _userManager;

  public AccountController(UserManager<AppUser> userManager)
  {
    _userManager = userManager;
  }

 // POST api/Account/
 [AllowAnonymous]
 [HttpPost]
 public async Task<IActionResult> Post(
 [FromBody] UserModel userModel)
 {
   if (!ModelState.IsValid)
   {
     return new BadRequestObjectResult(ModelState);
   }
   var user = new AppUser {UserName = userModel.UserName};

   IdentityResult idResult = 
   await _userManager.CreateAsync(user, userModel.Password);

   IActionResult errorResult = GetErrorResult(idResult);
   if (errorResult != null)
   {
     return errorResult;
   }
   //Put together a response
   string url = 
    Url.RouteUrl("GetUserById", new { userId = user.Id },
   Request.Scheme, Request.Host.ToUriComponent());
   Context.Response.Headers["Location"] = url;
   Context.Response.StatusCode = (int)HttpStatusCode.Created;

   return new ObjectResult(TypeAdapter.Adapt<UserModel>(user));
}

//GET api/Account/1
[HttpGet("{userId:int}", Name = "GetUserById"]
public async Task<IActionResult> GetUserById(int userId)
{
  var user = 
   await _userManager.FindByIdAsync(userId.ToString());

  return new ObjectResult(TypeAdapter.Adapt<UserModel>(user));
} 

private IActionResult GetErrorResult(IdentityResult result)
{
  if (!result.Succeeded)
  {
   if (result.Errors != null)
   {
     foreach (var error in result.Errors)
     {
         ModelState.AddModelError(error.Code, error.Description);
     }
   }
   return new BadRequestObjectResult(ModelState);
  }
  return null;
}

}
}

So there’s a fair amount going on here.  The Post method accepts a UserModel, validates it using the annotations on the class and returns a BadRequest response with the model errors if validation fails.  If it succeeds, it uses the UserManager that is included with Identity to attempt to create an AppUser.  If the create fails, we will build an error response and return it. If the create is successful, it will store this new AppUser in our database and will also populate its assigned UserId.  We’ll create an object response and use Mapster to map the AppUser back to a response UserModel, but we’ll also add a header to the response that points to the Get uri that can be used to retrieve the user.

Now let’s try this out.  Start your project and the Home page should be displayed. If you don’t have it installed already, install Postman.  Fire up Postman and lets perform a Post to our API to create a new user.

CreateUserPostman

Select POST from the method dropdown.  Set the url to {your api url}/Account. Here, mine is http://localhost:13171/Account.  Add a a Content-Type header and set it to application/json.  Put some json in the payload that will pass password validation:

{
 "userName": "RicoSuave",
 "password": "MyPassword_123",
 "confirmPassword": "MyPassword_123"
}

Now click the Send button.  The tabs on the bottom should show the response.  A new user with ID should be returned.  If you examine the Headers tab, you will also see the Location header we added to the response.  Take note of the ID and try out the GET that we added to retrieve the user as well.  Note that because our DB setup method in Startup.cs deletes the DB on each restart, your users will be lost with each run of your project. Feel free to change this.

Before we end, there’s one more change I want to make.  Most consumers expect our response to come across as camel-cased json.  In addition, we don’t want to transmit null values.  In json, we should just skip that property to keep our payload concise.  Open the Startup.cs class and in the ConfigureService method, replace the code to set our MvcOptions with the following:

services.Configure<MvcOptions>(options =>
{
  options.OutputFormatters.RemoveAll(
    f => f.Instance is XmlDataContractSerializerOutputFormatter);

  var formatter = options.OutputFormatters.FirstOrDefault(
    f => f.Instance is JsonOutputFormatter);

  var jsonFormatter = formatter?.Instance as JsonOutputFormatter;
  if (jsonFormatter != null)
  {
    jsonFormatter.SerializerSettings.ContractResolver = 
      new CamelCasePropertyNamesContractResolver();
    jsonFormatter.SerializerSettings.NullValueHandling = 
      NullValueHandling.Ignore;
  }
});

This will drop null values from our json formatting and camel case all properties by default.  Try out the API again to see the difference.

Next time, we’ll take a look at setting up a basic Aurelia project and calling our basic API.

Nozus Step 2: Setting up MVC 6 with Basic Logging

The previous post in this series covered basic MVC 6 API project setup. In this post, we’re going to build on that and set up some baseline logging functionality in the API.  We’ll continue to enhance logging as the project progresses.

We’ll start by setting up logging.  In our case, we’re going to use Serilog.  It’s the new kid on the block for .Net logging and looks like it combines some nice elements of structured data with basic log messages.  This can easily be swapped for NLog.  Right now there isn’t 5.0 support for Log4Net, but expect that to change.

If it’s not already available, open the Package Manager Console: Tools –> Nuget Package Manager –> Package Manager Console. In the package source, select your VNext package source and the Web.Api project. At the prompt:

PM> Install-Package Microsoft.Framework.ConfigurationModel.Json -includeprerelease
Installing NuGet package Microsoft.Framework.ConfigurationModel.Json.1.0.0-beta3.
PM> Install-Package Microsoft.Framework.Logging.Serilog -includeprerelease
Installing NuGet package Microsoft.Framework.Logging.Serilog.1.0.0-beta3.

So we just installed JSON configuration support (no more web.config) and support for Serilog.  Now lets add a config.json file.  Right click on the Web.Api project and Select Add –> New Item…  Select ASP.Net Configuration File.  This should correspond to a config.json file.  Just add the default json.config to the project, we’ll add some things to it in a later installment.  I lowercase the file name…optional.

We’re going to add logging into the Startup.cs now. Open Startup.cs, add a Configuration property, and set it in the constructor. This will set up config information from our config.json and will also add configuration in from any environment variables that may be set in the deployment environment.

 public Startup(IHostingEnvironment env)
 {
   // Setup configuration sources.
   Configuration = new Configuration()
   .AddJsonFile("config.json")
   .AddEnvironmentVariables();
 }

 public IConfiguration Configuration { get; set; }

Now we’ll update the ConfigureServices method.  Configure services sets up services in our DI container.  We’ll add in logging by calling AddLogging() and while we’re in here, we’ll go ahead and remove XML as a potential output format. Notice that AddLogging reads in the configuration we read in the constructor.  We’re going JSON only with these services. Why? Because I don’t really want to support XML. Leave it if you like.

 public void ConfigureServices(IServiceCollection services)
 {
 services.AddLogging(Configuration);
 services.AddMvc();
 services.Configure<MvcOptions>(options =>
 {
 options.OutputFormatters.RemoveAll(formatter =>
formatter.Instance is XmlDataContractSerializerOutputFormatter);
 });
 }

Next, we’ll configure the actual middleware pipeline.  For this we use the Configure method. It’s a little confusing that we have ConfigureServices (DI) and Configure (Pipeline), but that’s the convention.  We’ll add Serilog as our logger and create a method to set up our logger configuration. Serilog can alternately read from app settings if that is preferred and I’ll probably switch it over to do that at some point.  Notice here that I’m writing out to a rolling file on my D drive.  You can write to whatever location or writer works for you.

public void Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory)
{
  loggerfactory.AddSerilog(GetLoggerConfiguration());
  app.UseStaticFiles();
  // Add MVC to the request pipeline.
  app.UseMvc(routes =>
  {
    routes.MapRoute(
    name: "default",
    template: "{controller}/{action}/{id?}",
    defaults: new {
        controller = "Home",
        action = "Index" });
  });
}

private static LoggerConfiguration GetLoggerConfiguration()
{
 return new LoggerConfiguration()
 .Enrich.WithMachineName()
 .Enrich.WithProcessId()
 .Enrich.WithThreadId()
 .MinimumLevel.Debug()
 .WriteTo.RollingFile(@"D:\Logs\Nozus.Web.Api\file-{Date}.txt",
 outputTemplate:
 "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level}:{EventId} [{SourceContext}] {Message}{NewLine}{Exception}")
}

Now that we have the Serilog package installed, if you try to compile you might notice a problem.  The compiler has some complaints and if you look closely, you’ll notice that it’s complaining about Serilog but in addition that it’s complaining about ASP.Net Core 5.0.

CoreErrors

So if you’re not already aware, we have two flavors of .Net 5.0, the core flavor, which is being touted as the minimal/side-by-side/deployable/cloud flavor vs the full framework.  The problem here is that Serilog (and most other legacy .Net assemblies) won’t be compatible with the core flavor.  Expect this to change as .Net 5.0 goes live and the migration begins.  Right now we are compiling for both the Core and full flavors of the framework.  For now, we’re going to remove Core compilation from our project.  Open the project.json file and delete the core framework:

 "frameworks": {
     "aspnet50": { },
     "aspnetcore50": { }
 }

Now compilation should succeed.  Now let’s put in some basic logging to do an error catch all.  So there are a few ways to accomplish this.  One was is to use the built in ErrorHandling middleware.  To me, this is more geared towards MVC, where one wants to perform some logging and then perhaps render an alternate view from the standard. In my case since this is an API, I just want to log the error and send the standard 500 error out the door.  Perhaps I’ll add in a Production mode later that sends an alternate view out.  The nice thing is that since ASP.Net is now open source, we can see what the error handling middleware does and just make a simpler version of this when configuring services.  Since I just need something stupid simple, I added my own middleware.

In the Web.Api project add a Middleware folder.  In this folder create a new class called ErrorLoggingMiddleware.  It should look like this:

using System; using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Framework.Logging; 

namespace Nozus.Web.Api.Middleware
{
public class ErrorLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public ErrorLoggingMiddleware(RequestDelegate next,
ILoggerFactory loggerFactory)
{
  _next = next;
  _logger = loggerFactory.Create<ErrorLoggingMiddleware>();
} 

public async Task Invoke(HttpContext context)
{
  try
  {
    await _next(context);
  }
  catch (Exception ex)
  {
    _logger.WriteError("An unhandled exception has occurred: "
    + ex.Message, ex);
    throw; // Don't stop the error
  }
}
}
}

All we’re doing is logging the error and throwing it up the chain for eventual handling by the framework. One really nice thing is that you’ll notice our dependencies are injected into the middleware for us.  So middleware is now hooked into the core DI mechanism and is truly first class.  Very nice…  You can also see the basic middleware pattern.  This is the same basic OWIN pattern you may be used to: Middleware is a russian doll where the next middleware component is injected and wrapped by the current middleware component.  So in our case we just call the next middleware component and log something if there’s an error. Really easy, the possibilities for open-source/third-party middleware are huge.  I expect this to explode with Asp.Net 5.

So now we need to call our middleware.  In the Configure method, well use the AddMiddleware method to add in our custom middleware.

public void Configure(IApplicationBuilder app, 
IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
 loggerFactory.AddSerilog(GetLoggerConfiguration());

 app.UseStaticFiles();
 // Add MVC to the request pipeline.

 app.UseMiddleware<ErrorLoggingMiddleware>();

 app.UseMvc(routes =>
 {
   routes.MapRoute(
   name: "default",
   template: "{controller}/{action}/{id?}",
   defaults: new { 
        controller = "Home", 
        action = "Index" });
 });
 }

So easy and now we’re set.  One thing to remember is that the order of adding middleware determines the call sequence, so it’s important to add your component in the right place, which may differ depending on what you are trying to accomplish.

So now as a quick example, let’s log something from our home page by throwing an error from our default HomeController.  Just open the HomeController and have the Index method throw an error, something like:

[HttpGet("/")]
 public IActionResult Index()
 {
 throw new InvalidOperationException("Ghost in the machine!");
 return View();
 }

Let’s start up our app and it should immediately err since the error message gets thrown up the chain by our middleware.

ErrorShot

But if we go to our log file location that we set earlier, we should now have a log file with our error properly logged.

2015-03-11 21:02:58.723 -05:00 Error: [Nozus.Web.Api.Middleware.ErrorLoggingMiddleware] An unhandled exception has occurred: Ghost in the machine!
System.InvalidOperationException: Ghost in the machine!
 at Nozus.Web.Api.Controllers.HomeController.Index() in C:\Users\Visual Studio 14\Projects\Another\Nozus.Web.Api\Controllers\HomeController.cs:line 14
--- End of stack trace from previous location where exception was thrown --etc....

Just remember to remove the thrown error before proceeding further….in the next installment we’ll set up basic identity management…then we may switch over to Aurelia before getting back to social logins.

Nozus Step 1: Creating a Web API with MVC 6 – Project Setup

This article involves basic Visual Studio and project setup and should go fairly quickly.  I’m going to start out by creating a Web Api using MVC 6.  For reference, I’m using Visual Studio 2015 Preview 6.  Instead of beginning from complete scratch, I’m going to start with the Web API template.

From Visual Studio, go to File –> New –> Project.

In the New Project dialog box, select Web from the template tree and ASP.Net Web Application as the template.

NewProject

In the resulting web project template modal, select ASP.Net 5 Preview Web API. Note:  The Web API template is new with Preview 6.

NewProject2

Now lets add a couple of basic projects to our solution to round out the API.  A Domain class library for all Domain entities and interfaces, and a Data project for any repositories or EF 7 DataContexts.

Right click the solution node in the Solution Explorer and select Add –> New Project

NewProjectClassLib

InitialSolutionIn the Add New Project dialog, select ASP.Net 5 Class Library as the template. Do this twice:  Once for a .Domain project and once for a .Data project.  The initial structure should look something like the image to the right.

Now that some basic project structure is set up…lets add in some needed Nuget packages.  The first thing to do is to make sure the Nuget package manager is up to date.  You can go to Tools –> Extensions and Updates…  Look in the updates node on the navigation tree to see if there are any updates available for the Nuget Package Manager.

Now we need to set up the package manager such that it’s pointing to the correct source of packages for ASP.Net 5.

Open the Nuget settings by going to Tools –> Nuget Package Manager –> Package Manager Settings.  The Package Manager Settings dialog will open.

Navigate to Package Sources, and if it’s not already present, add an entry for AspNetVNext packages with source: https://www.myget.org/F/aspnetmaster/api/v2.

NugetSetup

Before we get started adding packages, lets make sure the packages we have are up to date.  Right click the solution node in the Solution Explorer and select Manage Nuget Packages…  In the Nuget Package Manager dialog, select the AspNetVNext source with Upgrade available and Include prerelease as filters. Install any available official M$ upgrades.

UpgradePackages

If you open your project.config in the Web.Api project, it should look something like the structure below.  We’ll talk more about this structure with the next installment.

{
 "webroot": "wwwroot",
 "version": "1.0.0-*",
 "dependencies": {
 "Microsoft.AspNet.Server.IIS": "1.0.0-beta3",
 "Microsoft.AspNet.Mvc": "6.0.0-beta3",
 "Microsoft.AspNet.StaticFiles": "1.0.0-beta3",
 "Microsoft.AspNet.Server.WebListener": "1.0.0-beta3",
 "System.Runtime": "4.0.20"
 },
 "frameworks": {
 "aspnet50": { },
 "aspnetcore50": { }
 },
 "exclude": [
 "wwwroot",
 "node_modules",
 "bower_components"
 ],
 "bundleExclude": [
 "node_modules",
 "bower_components",
 "**.kproj",
 "**.user",
 "**.vspscc"
 ]
}

Go ahead and run the Web.Api project.  The browser of your choice should launch and you should see a page like the following:

AppRunning

In the next article, we’ll set up basic logging and then identity management.