Creating an Angular application end-2-end – Part 1

Introduction

In this post series I want to demonstrate how to create a full blown application end-to-end which uses Angular JS on the client, ASP.NET vNext and/or Node JS on the server. Architectural patterns that I am going to use are command query responsibility segregation (CQRS), event sourcing (ES) and (some light) domain driven design (DDD). As a write store we will use GetEventStore. For our read models we use MongoDB and ElasticSearch.

I will develop the application on Linux Ubuntu 14.10 and also show that it runs without modifications on Windows 8.1 or Windows Server 2012.

Installing the Prerequisites

Make sure you have ready my post about creating and configuring a Ubuntu VM on Hyper-V

  • Creating an Ubuntu developer VM on Hyper-V 
  • Creating an Ubuntu developer VM on Hyper-V – Part 2
  • Creating an Ubuntu developer VM on Hyper-V – Part 3
  • Creating an Ubuntu developer VM on Hyper-V – Part 4

    If you are on a Mac the procedure should be very similar as described above except of course that you do not have to create a VM :-)

    Creating a server using ASP.NET vNext

    Installing Yeoman

    Yeoman is very helpful to jumpstart a new project. We can install it globally

    sudo npm install yo -g

    Since we are going to develop our first version of the backend using ASP.NET vNext we also want to install the asp.net generator for Yeoman

    sudo npm install generator-aspnet -g

    Creating and initializing a project folder

    Create a new project folder and navigate to it. Let’s call this folder recipes. In my case I create it in my ~/dev folder

    mkdir ~/dev/recipes
    cd ~/dev/recipes

    Let’s initialize a (local) git repository for this project

    git init

    and create a .gitignore file containing the following entries (we might add other entries as we need them)

    node_modules
    bower_components
    bin
    obj
    dist

    Next we init npm and bower

    npm init

    bower init

    Scaffolding the server side code

    Now we use Yeoman to generate an MVC type of application in a subfolder server of our project folder

    yo aspnet

    when asked for the type of application select MVC Application. When asked for the name of the application type server. Yeoman will create a subfolder server in our recipes folder. Navigate to this folder and restore the nuget packages used by the project

    cd server

    kpm restore

    and finally try to build the project

    kpm build

    if that works we can now start kestrel (the development web server)

    k kestrel

    and use e.g. Chrome to navigate to http://localhost:5004 to test our sample application

    image

    To stop kestrel simply press ENTER (and then CTRL-C) in the terminal where you started it.

    Defining a RESTful API

    All access to from the web client to the backend should be via a RESTful interface.

    The read side

    Since we are dealing with recipes in our sample application let’s define a REST API which allows us to either retrieve a list of recipes or a single recipe. First we define 2 data transfer objects (DTOs) NameId and RecipeDto in the Models folder

    namespace Recipes.Models
    {
        public class NameId{
            public int id { get; set; }
            public string name { get; set; }
        }
    }

    and

    namespace Recipes.Models
    {
        public class RecipeDto{
            public int id { get; set; }
            public string name { get; set; }
            public string category { get; set; }
            public string level { get; set; }
            public string cost { get; set; }
        }
    }

    In the controllers folder we add a RecipesController to our MVC project containing the following code

    using System;
    using System.Collections.Generic;
    using Microsoft.AspNet.Mvc;
    using Recipes.Models;
    
    namespace Recipes.Controllers
    {
        [Route("api/[controller]")]
        public class RecipesController : Controller
        {
            [HttpGet]
            public IEnumerable<NameId> Get()
            {
                return new [] { 
                    new NameId{ id= 1, name= "Spaghetti Carbonara" },
                    new NameId{ id= 2, name= "Risotto Milanese" },
                    new NameId{ id= 3, name= "Saltinbocca all Romana" },
                };
            }
    
            [HttpGet("{id}")]
            public RecipeDto Get(int id)
            {
                return new RecipeDto{
                    id= 1,
                    name= "Spaghetti Carbonara",
                    category= "Italian",
                    level= "easy",
                    cost= "low"
                };
            }
        }
    }

    The two overloads of the Get methods just return some pre-canned recipes.

    Save the files and compile. Then we navigate to the URI http://localhost:5004/api/recipes and http://localhost:5004/api/recipes/1 respectively and for the former should see something like this

    image

    Ok, apparently the reading part works fine. Now let’s tackle the writing part.

    The write side

    Since in this sample we are using CQRS and ES we will be sending commands from the client to the backend which will never contain the whole state of entities but rather the deltas of state change. We will be using the HTTP POST exclusively to send commands. We will also use routing to differentiate between different commands targeting the same type of object – here a recipe. That is if we have two commands “create a new draft recipe” and “submit recipe for review” then we will correspondingly define the two URIs

    api/recipes/create and

    api/recipes/submit

    to which we post the respective commands.

    Let’s implement the method for the create command. First we define the CreateRecipeCommand class in the Models folder

    public class CreateRecipeCommand{
    	public string name { get; set; }
    	public string category { get; set; }
    	public string userName { get; set; }
    }

    The least amount of information we need to provide to create a new recipe is the name of the new recipe, the category to which we want to associate the recipe and the unique user name of the person wanting to create this new draft recipe.

    Then we add the following method to the RecipesController class

    [Route("create")]
    [HttpPost]
    public int Create(CreateRecipeCommand cmd)
    {
        Console.WriteLine("Creating a new recipe");
        return 1;
    }

    and we can then test it by e.g. using the Postman plug-in for Chrome

    image

    and in the console we should also get a feedback that the method has indeed been called

    image

    The domain

    Now that we have successfully created and tested a read and write API we can start to implement the business logic. Here we are going to use concepts of domain driven design (DDD, see e.g. the blue book), namely aggregates, application services, repositories and factories. We do not want to implement any type of domain related logic in the API controller. The API controller’s sole goal is to route external web requests to the domain.

    First we create an application service which is providing the infrastructure for an aggregate. An aggregate is very self centric and should be unaware of the specifics of the infrastructure (i.e. from where it comes and where it is persisted to just name two concerns). Thus we create an application service which is responsible for all the things the aggregate shouldn’t care about.

    For convenience our application service has a When method for each command it is supposed to handle. Thus we will have a multitude of When methods on this service, each one with a single parameter. We also need to make sure that we do not use the DTOs that are exposed to the outside world (e.g. the CreateRecipeCommand, etc.) in the domain. We want to stay as much decoupled as possible. Thus we first define a DTO that we will use internally

    namespace Recipes.Domain{
    	public class CreateRecipe{
    		public string Name { get; set; }
    		public string Category { get; set; }
    		public string UserName { get; set; }
    	}
    }

    now we define a helper class with an extension method to map the external DTO to the internal one

    using Recipes.Models;
    
    namespace Recipes.Domain{
    	public static class ExtensExternalCommands{
    		public static CreateRecipe ToInternal(this CreateRecipeCommand c){
    			return new CreateRecipe{
    				Name = c.name,
    				Category = c.category,
    				UserName = c.userName
    			};
    		}
    	}
    }

    We have now what we need to define the Recipe application service

    namespace Recipes.Domain
    {
    	public class RecipeApplicationService
    	{
    		public int When(CreateRecipe cmd)
    		{
    			// create a new recipe aggregate
    			// and return the id of the newly created instance
    		}
    	}
    }

    Now, the application service will get a new instance of a Recipe aggregate from somewhere. For this we will use a repository represented by the interface IRepository that will be injected into the application service. The application service also needs to create a new unique id for the new aggregate. For this we use another service represented by the interface IUniqueKeyGenerator which will also be injected into the service. The code then looks like this

    namespace Recipes.Domain
    {
    	public class RecipeApplicationService
    	{
    		private IRepository repository;
    		private IUniqueKeyGenerator keyGenerator;
    
    		public RecipeApplicationService(IRepository repository, IUniqueKeyGenerator generator)
    		{
    			this.repository = repository;
    			this.keyGenerator = generator;
    		}
    
    		public int When(CreateRecipe cmd)
    		{
    			var id = keyGenerator.GetId<RecipeAggregate>();
    			Console.WriteLine("creating recipe aggregate with id={0}", id);	// for debugging...
    			var aggregate = repository.Get<RecipeAggregate>(id);
    			aggregate.Create(cmd.Name, cmd.Category, cmd.UserName);
    			repository.Save(aggregate);
    			return id;
    		}
    	}
    }

    We have of course not yet defined the interfaces IRepository, IUniqueKeyGenerator, IAggregate and also we have not yet defined the recipe aggregate. Here they are

    namespace Recipes.Domain
    {
    	public interface IRepository 
    	{
    		T Get<T>(int id) where T: IAggregate; 
    		void Save(IAggregate aggregate);
    	}
    }

    namespace Recipes.Domain
    {
    	public interface IUniqueKeyGenerator 
    	{
    		int GetId<T>();
    	}
    }

    namespace Recipes.Domain
    {
    	public interface IAggregate
    	{
    		int Id { get; }
    		int Version { get; }
    	}
    }

    namespace Recipes.Domain
    {
    	public class RecipeAggregate : IAggregate
    	{
    		public int Id { get; private set; }
    		public int Version { get; private set; }
    
    		public RecipeAggregate(int id)
    		{
    			Id = id;
    		}
    		
    		public void Create(string name, string category, string userName)
    		{
    			// TODO
    		}
    	}
    }

    Ok, now we can actually use this service in the RecipeController. Note that we also inject the RecipeApplicationService into the controller.

    private readonly RecipeApplicationService service;
    
    public RecipesController(RecipeApplicationService service)
    {
        this.service = service;
    }
    
    [Route("create")]
    [HttpPost]
    public int Create(CreateRecipeCommand cmd)
    {
        Console.WriteLine("creating recipe...");    // for debugging purposes...
        var newId = service.When(cmd.ToInternal());
        return newId;
    }
    

    Now we need to implement the unique key generator service. For this sample we keep it simple and just use a dictionary to store the last given key per entity type in memory. In a productive system we will have to persist the values to be resilient to server crashes or reboot.

    using System;
    using System.Collections.Generic;
    
    namespace Recipes.Domain
    {
    	public class UniqueKeyGenerator : IUniqueKeyGenerator
    	{
    		private readonly static object sync = new object();
    		private readonly Dictionary<Type,int> cache = new Dictionary<Type,int>();
    
    		public int GetId<T>()
    		{
    			lock(sync)
    			{
    				var key = typeof(T);
    				if(cache.ContainsKey(key) == false)
    					cache.Add(key, 0);
    				cache[key]++;
    				return cache[key];
    			}
    		}
    	}
    }

    Next in turn is the repository. We will use GetEventStore (GES) as our event store. But for the moment we just implement a fake repository that just uses a dictionary as an in-memory store. Later we will change the implementation and access GES

    using System;
    using System.Collections.Generic;
    
    namespace Recipes.Domain
    {
    	public class InMemoryRepository : IRepository
    	{
    		private readonly static object sync = new object();
    		private readonly Dictionary<Type, Dictionary<int, IAggregate>> cache =
    			new Dictionary<Type, Dictionary<int, IAggregate>>();
    
    		public T Get<T>(int id) where T : IAggregate
    		{
    			lock(sync)
    			{
    				var key = typeof(T);
    				if(cache.ContainsKey(key) == false)
    					cache[key] = new Dictionary<int, IAggregate>();
    				if(cache[key].ContainsKey(id) == false)
    					cache[key].Add(id, GetNewInstance<T>(id));
    				return (T)cache[key][id];
    			}
    		}
    
    		public void Save(IAggregate aggregate)
    		{
    			// TODO
    		}
    
    		private IAggregate GetNewInstance<T>(int id) where T : IAggregate
    		{
    			if(typeof(T) == typeof(RecipeAggregate))
    				return new RecipeAggregate(id);
    
    			throw new ArgumentException("Unexpected aggregate type");
    		}
    	}
    }

    There is only one thing missing now until we can have a test run. We need to wire up the dependencies. For this we configure an IoC container, either the default container provided with ASP.NET vNext or a third party one like AutoFac. In this sample we use the default container. We just have to modify the Startup class and add the three lines which define our services (lines 5-7)

    app.UseServices(services =>
    {
        services.AddMvc();
    
        services.AddTransient<RecipeApplicationService>();
        services.AddSingleton<IUniqueKeyGenerator, UniqueKeyGenerator>();
        services.AddSingleton<IRepository, InMemoryRepository>();
    });
    

    We can now compile what we have so far (kpm build) and run (k kestrel).

    And now we are ready to try what we have implemented so far. Let’s return to our Postman client and try to send the same command again that we have used earlier when we tested the controller.

    image

    In the console we should see a feedback, something like this

    image

    This is really cool! So, now the only piece missing until we have the write part of our server ready is the GES repository.

    Summary

    In this first part of the series about writing an Angular application end-2-end I have shown how to use ASP.NET vNext on Ubuntu 14.x to create a RESTful backend. In the next part I will further develop the domain and also implement a repository for GetEventStore. Stay tuned!

  • About Gabriel Schenker

    Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 25 years as a consultant, software architect, trainer, and mentor mainly on the .NET platform. He is currently working as senior software architect at Alien Vault in Austin, Texas. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process. Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.
    This entry was posted in AngularJS, ASP.NET vNext, REST, Ubuntu. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
    • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1771()

    • Ailsa Powell

      Nice explain of asp .net. I like it

    • Good job on creating a non-worthless Repository and for a reasonable usage of IRepository<T>

      You shouldn’t use a lock object, you should replace your usage of dictionary with ConcurrentDictionary and go lockless.

    • thefokko

      What IDE do you use?

      • gabrielschenker

        I use Sublime Text 3

    • Pingback: Creating an Angular application end-2-end – Part 1 | denhul()

    • toddbreyman

      It looks like you missed the code where the application service is injected in the controller. It appears that the IAggregate code is shown twice.

      • gabrielschenker

        Thanks for reporting it. Updated!

    • Jose Gregorio Taveras

      Why dont use automapper instead of the helper class to convert the command class to internal ?

    • I both like and dislike “public int When(CreateRecipe cmd)”. It reads great when reading the interface, but when you call it from the controller the intent is not clear.

      Also I don’t like the create method on the aggregate. Use the constructor, otherwise you are creating a invalid object.

      Other than that I like the flow. Map -> Operate -> Validate -> Save.

      Also pretty cool how easily you spin this up on Ubuntu.