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 -gSince 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 -gCreating 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
Let’s initialize a (local) git repository for this project
git initand create a .gitignore file containing the following entries (we might add other entries as we need them)
Next we init npm and bower
npm init bower initScaffolding the server side code
Now we use Yeoman to generate an MVC type of application in a subfolder server of our project folder
yo aspnetwhen 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 restoreand finally try to build the project
kpm buildif that works we can now start kestrel (the development web server)
k kestreland use e.g. Chrome to navigate to http://localhost:5004 to test our sample application
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
and
In the controllers folder we add a RecipesController to our MVC project containing the following code
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
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
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
and we can then test it by e.g. using the Postman plug-in for Chrome
and in the console we should also get a feedback that the method has indeed been called
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
now we define a helper class with an extension method to map the external DTO to the internal one
We have now what we need to define the Recipe application service
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
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
Ok, now we can actually use this service in the RecipeController. Note that we also inject the RecipeApplicationService into the controller.
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.
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
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)
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.
In the console we should see a feedback, something like this
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!</p>
-
- Creating an Ubuntu developer VM on Hyper-V – Part 3
- Creating an Ubuntu developer VM on Hyper-V – Part 2