Building a Web API on ASP.NET Core for our Aurelia SPA

ASP:NET Core Web API
Implementing a ASP.NET Core Web API for our Aurelia SPA

This post will focus on writing a Web API that will serve our Aurelia SPA with data. The Web API is built on ASP.NET Core and resides in it’s own project. We will be implementing the repository pattern and an in memory repository. A Class Library will be used to hold the model and the repository.

The “Aurelia SPA built with TypeScript and Sass on .NET Core” Series

These are the parts of this blog post series about building a SPA in Aurelia.

Part I – How to: Build an Aurelia SPA with TypeScript on ASP.NET Core
Part II – How to: Build a Web API on ASP.NET Core for an Aurelia SPA
Part III – How to: Fetching data from a Web API on ASP.NET Core to an Aurelia SPA
Part IV – How to: Creating Aurelia Custom Elements with TypeScript

Aim of this Post

First of all, the functionality of the SPA we’re building is to store and manage information about droids. The aim of this post, is to implement the storage layer and also the models for our data. When this post is done we will have a ASP.NET Core Web API that our Aurelia SPA can use. We’ll also have the base models in a Class Library, and use them from our Web API.

Defining the Model and Repository

The droids we’re going to operate on will have a sett of properties describing the object and some pertaining the object storage. The properties describing object storage (create date, change date) is not something we want to send to a client, so we will use a DTO (Data Transfer Objects) to decide what we want send to the clients.

Create the Droid Model

  1. First add a new folder to the Class Library, name it Model.
    Adding a new folder in Visual Studio
  2. Add a class in the new folder, name it Droid.cs
  3. Add a new folder to the Class Library named DTO.
  4. Add a new class in the DTO folder, name that Droid.cs as well.

So what information do we want to store about our droids?
First of we need identifying properties, like name and id’s.
Then we’d like a set of physical attributes listed, like height, weight, any eventual armaments etc.
We also want some meta data on the droid object, it’s good to know when it was created and modified.
Edit the Model.Droid.cs class like this:

using System;
using System.Collections.Generic;

namespace DWx.Repository.Model
{
    public class Droid
    {
        private DateTime CreateDate { get; } = DateTime.UtcNow;
        private DateTime EditDate { get; } = DateTime.UtcNow;
        private DateTime DeleteDate { get; } = DateTime.UtcNow;
        private bool IsDeleted { get; }

        public int Id { get; set; }
        public Guid ImperialContractId { get; set; }
        public string Name { get; set; }
        public long CreditBalance { get; set; }
        public string ProductSeries { get; set; }

        public decimal Height { get; set; }
        public decimal Weight { get; set; }
        public IEnumerable<string> Armaments { get; set; }
        public IEnumerable<string> Equipment { get; set; }

        public Droid()
        {
            CreateDate = DateTime.UtcNow;
            EditDate = DateTime.UtcNow;
            DeleteDate = DateTime.MinValue;
        }

        public Droid(DTO.Droid dtoDroid)
        {
            CreateDate = DateTime.UtcNow;
            EditDate = DateTime.UtcNow;
            DeleteDate = DateTime.MinValue;

            Id = dtoDroid.Id;
            ImperialContractId = dtoDroid.ImperialContractId;
            Name = dtoDroid.Name;
            CreditBalance = dtoDroid.CreditBalance;
            ProductSeries = dtoDroid.ProductSeries;
            Height = dtoDroid.Height;
            Weight = dtoDroid.Weight;
            Armaments = dtoDroid.Armaments;
            Equipment = dtoDroid.Equipment;
        }
    }
}

Edit the DTO.Droid.cs like this:

using System;
using System.Collections.Generic;

namespace DWx.Repository.DTO
{
    public class Droid
    {
        public Droid()
        {

        }
        public Droid(Model.Droid modelDroid)
        {
            Id = modelDroid.Id;
            ImperialContractId = modelDroid.ImperialContractId;
            Name = modelDroid.Name;
            CreditBalance = modelDroid.CreditBalance;
            ProductSeries = modelDroid.ProductSeries;
            Height = modelDroid.Height;
            Weight = modelDroid.Weight;
            Armaments = modelDroid.Armaments;
            Equipment = modelDroid.Equipment;
        }

        public int Id { get; set; }
        public Guid ImperialContractId { get; set; }
        public string Name { get; set; }
        public long CreditBalance { get; set; }
        public string ProductSeries { get; set; }

        public decimal Height { get; set; }
        public decimal Weight { get; set; }
        public IEnumerable<string> Armaments { get; set; }
        public IEnumerable<string> Equipment { get; set; }
    }
}

Create the Repository

What do we want our repository to do then?
First of all We want to specify an interface for the Repository! This way we can swap it around for other implementations later on, without breaking our contract.
This will also help with unit testing, as having an interface to adhere too makes it easy to substitute in mock classes for testing.

  1. Create a folder in the root of the Class Library named Repository.
  2. Create a new interface, name it IDroidRepository.cs
  3. Create a new class named DroidRepository.cs

Implement the Repository Interface

As for our repository we want to be able to perform the standard CRUD operations (Create, Read, Update and Delete), but also support partial update that will come in handy in our SPA.
Implement the repository interface like this:

using System.Collections.Generic;
using DWx.Repository.DTO;

namespace DWx.Repository.Repository
{
    public interface IDroidRepository
    {
        IEnumerable<Droid> GetAll();
        bool Create(Droid newDroid);
        Droid Get(int id);
        Droid Update(Droid droid);
        Droid Delete(int id);
    }
}

Implement the Repository Methods

Time to start with some real implementation.
Open the DroidRepository.cs file, and make it derive from the IDroidRepository interface. To speed up development you can put your cursor and use “the light bulb” and make it implement the interface.
Implementing an Interface in VS2015
As for data storage we’re just going to use a dictionary to start with. So no real persistence layer, yet. As it’s only one static dictionary keeping the data, we can end up with multiple calls from multiple threads at the same time, so we need to use the ConcurrentDictionary implementation.

Then implement the repository, the following is the one I use:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using DWx.Repository.DTO;

namespace DWx.Repository.Repository
{
    public class DroidRepository : IDroidRepository
    {
        private static ConcurrentDictionary<int, Model.Droid> repo { get; } = new ConcurrentDictionary<int, Model.Droid>();
        private static int id;
        public DroidRepository()
        {
            Seed();
        }

        public bool Create(Droid newDroid)
        {
            var droid = new Model.Droid(newDroid);
            newDroid.Id = id++;
            repo.TryAdd(newDroid.Id, new Model.Droid(newDroid));
            return true;
        }

        public Droid Delete(int id)
        {
            Model.Droid modelDroid;
            repo.TryRemove(id, out modelDroid);
            return new Droid(modelDroid);
        }

        public Droid Get(int id)
        {
            var droid = repo.Values.FirstOrDefault(d => d.Id == id);
            if (droid != null)
            {
                return new Droid(droid);
            }
            return null;
        }

        public IEnumerable<Droid> GetAll()
        {
            var droids = new List<Droid>();
            foreach (var droid in repo.Values)
            {
                var newDroid = new Droid(droid);
                droids.Add(newDroid);
            }
            return droids.OrderBy(d => d.Id);
        }

        public Droid Update(Droid droid)
        {
            if (repo.ContainsKey(droid.Id))
            {
                droid.Id = repo[droid.Id].Id;
                repo[droid.Id] = new Model.Droid(droid);
                return droid;
            }
            return null;
        }

        /// <summary>
        /// Seed the database with a few initial droids
        /// </summary>
        private static void Seed()
        {
            var ig88B = new Model.Droid
            {
                Id = id++,
                ImperialContractId = Guid.Parse("0B450FDD-F484-423B-8685-4193E9FA583D"),
                Name = "IG-88B",
                CreditBalance = 4500000,
                ProductSeries = "IG-88",
                Height = 1.96M,
                Armaments = new List<string> {
                    "DAS-430 Neural Inhibitor", "Heavy pulse cannon", "Poison darts",
                    "Toxic gas dispensers", "Vibroblades"
                },
                Equipment = new List<string>()
            };
            repo.TryAdd(ig88B.Id, ig88B);

            var c3po = new Model.Droid
            {
                Id = id++,
                Name = "C-3PO",
                ProductSeries = "3PO-series Protocol Droid",
                Height = 1.71M,
                Armaments = new List<string>(),
                Equipment = new List<string>
                {
                    "TranLang III communication module"
                }
            };
            repo.TryAdd(c3po.Id, c3po);

            var r2d2 = new Model.Droid
            {
                Id = id++,
                Name = "R2-D2",
                ProductSeries = "R-Series",
                Height = 0.96M,
                Armaments = new List<string> {
                    "Buzz saw", "Electric pike"
                },
                Equipment = new List<string>
                {
                    "Drinks tray (only on sail barge)", "Fusion welder",
                    "Com link", "Power recharge coupler",
                    "Rocket boosters", "Holographic projector/recorder",
                    "Motorized, all-terrain treads", "Retractable third leg",
                    "Periscope", "Fire extinguisher", "Hidden lightsaber compartment with ejector",
                    "Data probe", "Life-form scanner", "Utility arm"
                }
            };
            repo.TryAdd(r2d2.Id, r2d2);
        }
    }
}

Add the Repository to the ASP.NET Core Dependency Injection System

Last thing we need to do is add the repository to the Dependency Injection system in ASP.NET Core, so that it can be inject into, and used from our controllers.
Open Startup.cs and modify ConfigureServices like this:

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();

            //DI
            services.AddSingleton<IDroidRepository, DroidRepository>();
        }

Implementing the Web API

Finally time to start working on the Web API!
But before we start implementing the actual methods, we need to change a few things in the setup of the project.

Preparing the Web API Project

To make the development experience a little smoother, add the watch tool to the Web API project if you haven’t already done so. (See the first episode of this post series if you don’t know how)

Then we want to change the base address to localhost:5005 instead of localhost:5000(as port 5000 is used by the Aurelia SPA). Modify the WebHostBuilder creation in Program.cs by adding a call to USeUrls(). Program.cs should look something like this:

  public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .UseUrls("http://localhost:5005")
                .Build();

            host.Run();
        }

Adding a Reference to the Repository Library

To access the repository functionality we implemented, we need to import a reference to our Class Library DWx.Repository.

Using Visual Studio

Right click the References node in the DWx.API project and select Add Reference….
VS2015 Add References

Not Using an IDE

It’s also possible to just edit the project.json file. (This option is going away soonβ„’ though, so enjoy it while it lasts!)
Just open the project.json file and add the following line under the dependencies section:

"DWx.Repository": "1.0.0-*"

Adding a Controller

Controllers are what’s used to serve the clients with information from a Web API.

So now add a class called DroidsController in the Web API under the Controllers folder.
If you got the ValuesController.cs left you can remove it, as it’s just examples created with the project.

The base implementation of the DroidsController should look like this:

using DWx.Repository.Repository;
using Microsoft.AspNetCore.Mvc;

namespace DWx.API.Controllers
{
   [Route("api/[controller]")]
    public class DroidsController
    {
        readonly IDroidRepository droidRepo;
        public DroidsController(IDroidRepository repository)
        {
            droidRepo = repository;
        }
    }
}

Implementing the GetAll Method

Add a method to the DroidsController class called GetAll.
Implement it like this:

        [HttpGet]
        public IActionResult GetAll()
        {
            var droids = droidRepo.GetAll();
            return new OkObjectResult(droids);
        }
Testing the Web API

Open a CLI and navigate to the root of the Web API Project. Start the server with dotnet watch run.

Now we can test the GetAll method we just implemented with some tool that can fire of web requests, for ex Postman.
In Postman call localhost:5005 with a GET and see what happens. It should return an array of Droids, the ones we defined in the Seed method in the DroidRepository.
Web API test of GetAll with Postman

Implementing the GetById Method

Add a method to the DroidsController class called GetById.
In this method we’re going to use the Http attribute to name it, because we want to reference this method by name later on. Implement the method like this:

        [HttpGet("{id}", Name = nameof(GetById))]
        public IActionResult GetById(int id)
        {
            var droid = droidRepo.Get(id);
            if (droid == null)
            {
                return new NotFoundObjectResult(
                    new Error
                    {
                        HttpCode = 404,
                        Message = $"Droid with id:{id} - No such Droid in database!"
                    }
                );
            }
            return new OkObjectResult(droidRepo.Get(id));
        }

Testing it with postman by sending a GET for id 0 gives:
Web API test of GetById with Postman

Implementing the Create Method

Add a method to the DroidsController class called Create.
Implement it like this:

        [HttpPost]
        public IActionResult Create([FromBody] Droid droid)
        {
            if (!ModelState.IsValid)
            {
                return new BadRequestObjectResult(new Error
                {
                    HttpCode = 400,
                    Message = $"Invalid payload: {ModelState}"
                });
            }

            var result = droidRepo.Create(droid);
            return new CreatedAtRouteResult(nameof(GetById), new { id = droid.Id }, droid);
        }

Visual Studio will mark ModelState with a squiggly, as it doesn’t know what this is yet. Easiest way to get access to ModelState is to derive our class from Controller, so just do that for the class and this will compile.

    public class DroidsController : Controller

When testing this with Postman, we issue a Post to localhost:5005 with the droid object in the body of the call. We also need to set a header for this to work, namely Content-Type that needs to be set to application/json.
Testing the Create call with Postman:
Testing Web API Create with Postman

Implementing the Delete Method

Add a method to the DroidsController class, called Delete.
Implement it like this:

        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            var result = droidRepo.Delete(id);

            if (result == null)
            {
                return new BadRequestObjectResult(new Error
                {
                    HttpCode = 404,
                    Message = "No such Droid in database!"
                });
            }

            return new NoContentResult();
        }

There’s two schools on what to return from a Delete in a Web API, some say return a status code and some say return the deleted object. This method returns a 204 No Content on successful removal of a droid.

Using Postman to test the Delete method:
Testing the Delete method of the Web API with Postman

Implementing the Update Method

Add a method to the DroidsController class, called Update.
Implement it like this:

        [HttpPut]
        public IActionResult Update([FromBody] Droid droid)
        {
            if (!ModelState.IsValid)
            {
                return new BadRequestObjectResult(new Error
                {
                    HttpCode = 400,
                    Message = "Invalid payload"
                });
            }

            var result = droidRepo.Update(droid);

            if (result == null)
            {
                return new NotFoundObjectResult(new Error
                {
                    HttpCode = 410,
                    Message = "Could not find Droid in database!"
                });
            }

            return new OkObjectResult(droid);
        }

Just as with the Create method, the Content-Type header needs to be set to application/json.

Testing the Update by removing a IG-88 it’s armaments:
Testing the Web API Update

Next Part – Fetching Data from the API in our Aurelia SPA!

In the next episode we’ll get the Web API going with serving data to our SPA. Will it be straight forward or will we run in to any surprises? πŸ™‚

We’ll also create a first view in Aurelia to show some data. And who knows, maybe we’ll have time to implement our applications first Aurelia element!

Get the Code

The code for this blog series is available on my GitHub repo, you can find it here: DWx-Aurelia-dotNETCore

Until next time,
Happy Coding! πŸ™‚

Some Additional Reading on ASP.NET Core Web API’s

About setting up a minimum viable Web API on ASP.NET Core:
Minimal Web API on ASP.NET Core

On Attribute routing and all it’s intricacies:
How to Master ASP.NET Core Web API Attribute Routing

On using SSL in development for ASP.NET Core:
ASP.NET Core – IIS Express and SSL

How to: Build a Web API on ASP.NET Core for an Aurelia SPA
Tagged on:                                 

6 thoughts on “How to: Build a Web API on ASP.NET Core for an Aurelia SPA

Leave a Reply

Your email address will not be published. Required fields are marked *