Effortlessly Scaffold Your App With Docker Part one graphicDockerize your next ASP.NET Core, Postgres and Angular app to easily get up and running.

Abstract

In this tutorial, you’ll learn how to use Docker to set up a fresh .NET Core project connected to a PostgreSQL database. As we’ll find, Docker will take care of all the heavy lifting when it comes to installing these packages and coordinating their execution. In fact, it’s so easy to develop using containers, we’ll throw in an Angular app just because we can! By the end, we’ll have a full web-app framework in place, replete with a client, REST API and database.

Show me the code

Go and get the final project template here.

To run the app, first make sure Docker and Docker-Compose are installed on your machine, and then:

That’s it! After a few minutes, you’ll be able to visit the Angular app at localhost:4200 and the REST API at localhost:5000.

Read on to understand how this was built up from scratch.  We’ll step through a Docker-oriented workflow with each piece of the app and glean some useful patterns for using containers during development. This crash-course in full-stack web development will serve as a helpful case study for hooking up an ASP.NET to a non-Microsoft database, building out a minimal REST API to be consumed by an Angular client and using Docker to hold it all together.

Application structure

We’ve been tasked to develop a web app for the international retail juggernaut Gadget Depot.

  • The CTO has one requirement: display Gadget Depot’s current inventory.
  • The budget is $50,000.
  • It needs to be done in 30 minutes.

Good thing we’re standing on the shoulders of containerized giants. We’re going to accomplish this with a .NET Core Web API, backed by PostgreSQL and consumed by an Angular client.

Start the timer, and let’s code!

Pick a spot in your file system, and make the root project directory.

It’ll be nice to keep the server code and client code entirely separate. The backend will be merely an API service. No C# code will be responsible for presentation. All the UI code will be in its own module, set up to consume our API.

To indicate the independence of the frontend and backend, make two sub-directories in the root of the project.

Now we need to scaffold out the boilerplate code for both of our projects. Nothing stops us from writing it all by hand, following the completed code as a guide. However, Microsoft and Angular each provide tools for generating starter-templates. We’ll use those tools (.NET Core CLI and [Angular CLI) to save us some time and tedium.

Scaffold .NET Core backend

Let’s scaffold the backend first, using the dotnet program.

In the backend directory, you should have a file tree resembling the following:

 

│   GadgetDepot.sln

└───GadgetDepot

│   appsettings.Development.json

│   appsettings.json

│   GagdetDepot.csproj

│   Program.cs

│   Startup.cs

├───bin

├───Controllers

├───Models

├───obj

└───Properties

 

Notice that we used a dockerized dotnet executable. Maybe you already had the dotnet program installed on your OS — could you just use that?  Perhaps. One concern is which version of dotnet are you running. And, if you update your system-wide dotnet for this project, would you then break your SDK for existing projects in your environment? These are tough questions.

Docker to the rescue!

We were able to scaffold all this code through without needing to worry about the specifics of the host machine we’re using to build this app.

Scaffold Angular frontend

No surprise: We can also leverage Docker for creating our Angular app!

Go back to the root of our project, and on into the frontend directory.

To generate code for a simple Angular app, the command to run is ng new gadgets --minimal --directory ./. Without needing to install the ng program, we’re going to use a Docker image that contains the Angular CLI tool.

This command readies an app template and installs a boatload of NodeJS modules. After a few minutes of installation, you should have a fully-loaded and operational Angular app.

The last step is to arrange our separate app components so that they boot up in such a way that they can network with each other.

Docker-Compose enters the ring

To orchestrate multiple containers, we’ll use Docker Compose. It’s a handy tool for configuring your containerized apps to work together.

We’re moving fast. If you haven’t seen Docker-Compose, or Docker, there are a plethora of useful tutorials out on the net. Try this one or this one. If need be, go acquaint yourself then come back – otherwise, we can march on.

In the root of the project, create a file docker-compose.yml.

In this file, we declare our three separate services comprising the app.

  •     web : the .NET Core Web API project
  •     db : the database
  •     client : the Angular app

One piece especially worth pointing out is the local_postgres_data volume. By declaring a “volume,” we can persist our database state beyond the lifetime of the db container. The call to create a volume allocates space on the host OS which outlives the destruction of a container. When we reboot our PostgreSQL service, the database will have retained all its tables and rows, ready to go as if nothing had happened.  If we didn’t map the container’s /var/lib/postgresql/data dir to our host filesystem, the container would boot with fresh state when created. In some cases, you might want this behavior! But for development, it’s convenient to persist some of your data.

Notice that web and client services specify a build property. This property tells Docker where to look for a Dockerfile it can use to build the containers. Right now, it wouldn’t find one since we haven’t created it. So let’s add a Dockerfile to each the ./Frontend and ./Backend directories.

For the backend:

For the frontend:

Each of these are very similar and straightforward. After specifying a base image, most of their steps pertain to an entrypoint.sh script, which will get run by default when the container starts. We need to provide this shell script.

Write the Startup scripts

For the last bit of Docker plumbing, we need to write an entry script for each of our services. This script acts as the ‘bootup’ command for the containers. The frontend and the backend scripts resemble each other closely – they each install dependencies and start a dev server.

For ./Backend/entrypoint.sh

For ./Frontend/entrypoint.sh

The .NET script restores its packages, updates the database, then runs a server in dev mode. The Angular script installs packages and boots up a dev server.

Easy as pie!

Now, for the grand finale, we can boot up our whole, orchestrated app with a single command in the root directory:

With one line, all the containers will build and configure themselves, ready to display the inventory listing for Gadget Depot! Get ready to cash that check!

Well – not quite!

In the next blog, we’ll add Postgres to our application and build out our API code.

Leave a comment

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