How to easily make a simple web: Using ASP.NET Core 2.0 and Docker

Gabriel Steinberg
Jan 24, 2018 · 36 min read
Image for post
Image for post

ASP.NET is the second most used server-side framework(According to the plot below), with ASP.NET Core being its successor it’s worth learning it. This guide will teach you the basics by making a website from scratch.

Image for post
Image for post

After making the website you would normally want to deploy it, you are sure that it works, you have tested it thousands of times in a dozen different scenarios but Alas! when you upload the app to your deployment server it doesn’t work. Remember that dependency that you installed that one time when starting the project? Yeah, that’s missing on the server.

Of course you could keep track of every dependency and framework making sure that your deployment environment is the same as your working environment, but that could grow very cumbersome very fast. Docker comes to solve this problem, making the whole environment contained in a convenient container, which you can deploy anywhere that supports docker, not having to worry if said server has any dependencies installed.

I will be guiding you on how to create a web page using ASP.NET Core 2.0 then, install Docker and create a container of the web app created, and at the end deploy it on Microsoft Azure Services.

Image for post
Image for post
A typical Visual Studio Code screen


  • Basic C# and HTML knowledge

I will be using Windows 10 OS and Visual Studio Code, the last one being open source under MIT license and cross platform supported in Windows, Mac OS and Linux, it’s not necessary for completing this tutorial but I recommend it for developing with ASP.NET for its debugging functions, still feel free to use your favorite editor.

Visual Studio Code:

Image for post
Image for post
.NET Core Logo

ASP.NET Core 2.0

So what is ASP.NET Core exactly ?

From Microsoft ASP.NET Core documentation:

“ ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-based, Internet-connected applications.”

So ASP.NET Core is a framework that provides tools to build web apps or Web APIs for both: back-end and front-end. Supporting HTML, CSS and JavaScript, as well as a way to dynamically generate views using a combination of HTML and C# in the front end, and modules built in C# to facilitate the building of the back-end. It can be easily integrated with many of the most popular front-end frameworks. It also provides a server to run as its own process when you start an ASP.NET application, to read more:

ASP.NET Core can be ran on top of the .NET Framework or on top of the .NET Core Framework, you can choose which.

But what is exactly the .NET Framework or the .NET Core Framework?

Basically either one provides:

  • A class library: A set of classes and modules that is common to all .NET applications, it follows the .NET standard which is a specification for how these modules should work. More details on here:
  • A Run-time Environment: Historically applications are written on a given language(e.g.: C/C++, Pascal, Fortran) and then compiled to machine language. With a run-time environment, the language(With .NET Core usually: C#, VB.NET, F#) is compiled(in this case it’s actually called transpiled) to a common language, called common intermediate language, and then the framework’s run-time environment reads this code and compiles it at run-time(Hence the name) to machine language.
Image for post
Image for post

This allows for cross-code compatibility, portability and app cross-platform compatibility. More details on:

  • Application Frameworks: When you open an application in Windows OS, you normally see (redundantly) a windows which handles User Interface, connection with any data you need and application flow, this is a windows form, which is an application framework. An application framework defines a way that the applications are structured and how they interact with the user. In fact, ASP.NET Core is an Application Framework, executing a console application which is a server, and giving the developer tools to define how this server interacts with clients.

For more information on the structure of .NET:

We saw what both frameworks provides but we haven’t seen the differences between them yet. The key difference between both frameworks is that .NET Core allows for cross-platform compatibility while .NET Framework only works on windows, yet the latter being older has support for technologies that are not yet supported by .NET Core, either because the support will be added in a later version, or it’s a deprecated technology and support will never be added.

Another difference which is even more important for us, is that .NET Framework doesn’t support Docker, so that’s a deal breaker, meaning we will be using .NET Core. For more differences and information:

Image for post
Image for post

This example

The Code:

How the site will look like:

This will be a simple guide, step-by-step on how to create a simple MVC page. We will start from the installation process of ASP.NET Core 2.0, and we will then make a page with an SQLite database.

We will take many intermediate steps trying to understand what is happening and what we are doing. We will not be using Code Scaffolding, which is a nice .NET Core option to rapidly generate some code that is repetitive, for the sake of better understanding. Yet we will be using scaffolding to generate the database because it’s not the focus of this guide, we will only be using it to demonstrate the Model part of the MVC structure.

The idea of the web page will be really simple, our focus is not to make a complete and secure web app but to try and understand ASP.NET Core and get a feeling of why it’s awesome. The page itself will be(It’s really a simple clone of an Argentinian site just a site for complaining about companies, the idea is that anyone can submit their complaint and that anyone can see the list of all the complaints submitted in a neat table.

So having this in mind, let’s get our hands dirty. 💪

Image for post
Image for post

Building the web

Step 1. Install .NET Core.

Follow this link:

Click on download .NET SDK, save it, open it and follow the installation wizard.

Step 2. Creating the ASP.NET Core 2.0 example

Create a folder named yourComplaint wherever you like, then open a command prompt if you are in windows or a terminal in Linux/mac, navigate to the directory where you created the folder and type the following commands:

After dotnet new web finalizes, the command line should say: Restore succeeded . After which, if we go to the folder yourComplaint we should see a directory structure like:

Image for post
Image for post
Directories inside yourComplaint

before continuing let’s see if everything is working correctly. Go back to your command prompt and type dotnet run it can take a little while to run but after that it should say:

so open http://localhost:5000 in your favorite browser.

Image for post
Image for post
Our first screen in ASP.NET Core

Surprise! A white screen with a little black “hello world!” in the left top corner, not very interesting, but we already have a server set up serving the words “Hello World!”.

Now let’s analyze what is happening, first the dotnet new web created an “Empty” ASP.NET Core structure, in contrast to other dotnet new commands which creates templates assuming some structure(you could try for example dotnet new mvc in another folder and run that one. To find out more options for dotnet new follow this link: ).

Coming back to our project, let’s see what is inside of it, first there is an archive yourComplaint.csproj this tells .NET which are the dependencies in our project, we will not pay much attention to this one yet. Then you have the Program.cs, Let’s open it.

If you are using Visual Studio Code, open the yourComplaint folder, it will ask you if you want to install ms-vscode.csharp go ahead and do it, then it will ask you to add assets for debugging, do that too it will come in handy later.

So the Main method here is the entry point for your program, it’s actually building your Web Server, using the method provided below BuildWebHost which creates a Kestrel Server(To read more: Pay special attention to the UseStartup<Startup> part, this is a method which tells the program to use the Startup class inside our Startup.cs to initialize services and configure the HTTP pipeline(Which we will look at after this).

Then we have the Startup.cs, go ahead and open it up you should see this:

We have two methods, ConfigureServices, which we will ignore for now, and Configure, both inside startup, which our server already knows that it should use(Remember what we talked about above).

The Configure method tells the server how to handle HTTP requests, ignoring the if block(Which basically tells us that if we are in developing mode it should use the developer exception page for any errors), we have the method, which is called every time an HTTP request arrives at our application. It just tells the server to respond to any request with “Hello World!”, what does any request mean? it means ANY request, so if you go to http://localhost:5000/test you will see the same “Hello World”.

Finally we see that we have the wwwroot folder which is empty, this folder will hold any static file. The obj and bin folders are the .NET Core dependencies and we will not be touching that. Also now we have a .vscode folder that Visual Studio Code uses for Debugging, a feature that we will be using in a while. For now head up to your command prompt(Or terminal) and hit CTRL+C to shutdown the server.

Pre-Step 3. The MVC architecture

This sections gives a very brief introduction to the MVC design pattern, it’s only for those who are not familiar at all with this topic. Those who have a basic grasp on MVC, feel free to skip ahead to Step 3.

Image for post
Image for post

The MVC architecture defines a design pattern on how an application should be structure, and it’s not exclusive to Web Applications(although we will be focusing on that case).


“The Model-View-Controller (MVC) architectural pattern separates an application into three main groups of components: Models, Views, and Controllers. This pattern helps to achieve separation of concerns. Using this pattern, user requests are routed to a Controller which is responsible for working with the Model to perform user actions and/or retrieve results of queries. The Controller chooses the View to display to the user, and provides it with any Model data it requires.”

So for a web app what this means is, that as soon as an HTTP request arrives at the server, it should be given to a controller, the controller should retrieve or submit whatever was asked for from the model. Based on the result the controller should give this to a view, which based on this data it should be rendered(And handed to the client in the shape of HTML+CSS+JavaScript).

A very important concept is separation of concerns, meaning that each part of the architecture should only manipulate what is its responsibility. So Model should only concern with business logic.

So to sum up, these are the responsibilities for each part:

Model: The model should handle the shape of the data and its validation and the business logic.

Controller: It should select what views to render given the request, hand data to the view or to the model or both and retrieve the data from the Model for the view.

View: It should handle how to present the data and how to send data back to the server given an interaction with the client, as well as any UI.

This is all too abstract, but we will be making our application use this architecture and you will get a better feeling of what it is. For more information on this pattern

Step 3. Add MVC Service and routing

What we are going to do now, is tell the ASP.NET Core application that we are going to be doing an MVC application. So go back to your startup.cs file and modify the ConfigureServices to look like this:

Basically, we just added the services.AddMvc(); line.

The ConfigureServices Method according to the ASP.NET Core documentation is:

“The ConfigureServices method is:


Called by the web host before the Configure method to configure the app's services.

Where configuration options are set by convention.

Adding services to the service container makes them available within the app and in the Configure method. The services are resolved via dependency injection or from IApplicationBuilder.ApplicationServices.”

What this means is that: here, we tell the application which services we will be using, services here informally meaning bundles of functions and behaviors (A more formal definition on the dependency injection page also for a deeper understanding of Configuring Services and Dependency Injection go here: ).

In this case we are calling the service.AddMvc which is part of the IServiceCollection which expose a number of services we can add to our app. In particular AddMvc tells the Run-time Environment “Hey, I want you to run like an MVC”, giving us a directory structure, Razor Syntax for the views which we will get into later, and a bunch of useful and cool methods among other things. For more information on AddMvc go to:

Then services configured in ConfigureServices exposes functions for our Configure method, we will now be changing that second function so that it starts making our MVC application use said functions.

First in the Configure Method eliminate the lines:

and then, after the ifcloses add the following lines:

So now the whole Configure method should look like:

So before continuing let’s debug our app from visual studio code, to do this simply press F5 to start debugging and to stop debugging press SHIFT + F5. This is pretty similar to using the dotnet run command(But with a bunch of extra function for debugging, as expected, yet we will not be using those in this tutorial), so be sure you don’t have any prompt running on this project, it will lead into a conflict. So go ahead, save and do it.

Visual Code automatically opens a window in your default browser, connected to our ASP.NET Core application, but there is nothing, just a white screen.

So what is happening? Remember that the configure method tells our app what to do when an HTTP request arrives. With the lines we added, using the routes.MapRoute method we are telling our server how to handle a request matching it to a route. This means that it will look for what comes after the first slash at the end of the URL http://localhost:5000. with an URL http://localhost:5000/<controllerName>/<action>/<id>?<arguments> the first thing after the slash will be matched to a controller, it will look for it inside the folder Controllers with the name <controllerName>Controller.cs, the second slash will be matched with an action(we will come back to that later, for now think of it as a method of the controller) which will be looked for inside the matched controller, and everything after are arguments for the action, Finally invoking <controllerName>.<action>(id = <id>, <arguments>)(the id argument is optional).

Image for post
Image for post
How routing matches the URL http://localhost:5000/sample/sampleAction/maybeID

So for example with the URL request http://localhost:5000/sample/sampleAction/maybeID?argument1=arg our application will look for sampleController.cs inside the Controllers folder, and call sample.sampleAction(id=maybeId,argument1=arg)(Normally IDs are numbers).

So what happened with our URL request http://localhost:5000/ opened by VS Code(Visual Studio Code)? Well, actually we are telling our app what to look for, the {controller=Home} tells it that if there is no controller specified it will default to the Home controller, and {action=Index} is defaulting to look for the index method and calling it with no arguments(Since our ID is optional thanks to the “?” indicator). Since the controller doesn’t even exist it will not find it and never returns anything.

For more information on routing:

Now a white screen is boring, we want the “Hello World” back! then let’s make a controller that gives us exactly that.

Step 4. Making our first Controller, the Home Controller

First, let’s stop debugging with Visual Studio Code pressing SHIFT+F5, now let’s see our current structure. Click on the symbol in the left top corner:

Image for post
Image for post

If it’s not already clicked, this will show the explorer where you can see your folder structure. Currently it should look like this:

Image for post
Image for post

As we saw previously, the MVC looks for the controller inside the Controllers folder, and it will look for the archive <controllerName>Controller.cs inside it. So let’s create a folder Controllers in the root of the project with HomeController.cs inside, Now the directory should look like:

Image for post
Image for post

Well now let’s add the basic structure of a Controller, which should be part of the yourComplaint.Controllers namespace and it should be a class named HomeController that inherits from Controller:

This simply creates the class HomeController as a controller, with some sensible and some required Dependencies. We know that our MVC app will default to look for the action index, so what is exactly an action? Well simply put an action is any method inside a Controller (Except for those particularly told not to be actions) and they should be “activated” due to clients’ requests.

So let’s create an action to get our “Hello World” back. We will just add a method that returns the “Hello World” string, so adding this method the controller will be:

Now press F5 and see what is happening. Yay! the “Hello World” is back enhanced with a smiling face. Now when the request http://localhost:5000/ arrives to the server, it defaults to look for the Home Controller, it finds it, and inside it, the Index method, which returns a “Hello World! :)” in plain text which is sent in plain HTML back to the client.

The reader with a sharp eye will have a question, Wasn’t presenting content a responsibility of the View? And yes, you are right, we are delegating a responsibility of the View to the Controller which is not right. So we will fix that in our next step.

Step 5. Adding our first View.

So first let’s make a little experiment, change our Index method in HomeController for:

Now the HomeController is returning a View; View() is a method in the MVC that tells the app to render and respond with the View corresponding to that action, which should be located in Views\<Controller Name>\<Action Name>.cshtml, the controller name folder should not have the “Controller” suffix, it will be clearer in a moment.

The View() method returns an IActionResult which is an interface for the result of this kind of actions, such as rendering a view.

But before creating a view let’s try running this code. As expected an error is thrown, we haven’t created the View. But this error has some interesting information.

Image for post
Image for post

This is telling us, that the MVC framework is looking for the specific view inside /Views/Home/Index.cshtml first and then inside Views/Shared/Index.cshtml, while the first one is the one that we will be creating, every view action looks for the view inside the View/Shared folder if it couldn’t find it in the View/<Controller> folder, so there you can make any view shared by all the controllers.

Now let’s go ahead, stop debugging and create the Views folder in the root of our application, inside of it make the Home folder and inside make an archive named Index.cshtml, which is the structure that we have talked about previously.

So here is what our directory tree should look like now:

Image for post
Image for post

We created Index.cshtml, the .cshtml indicates a Razor File, which is allowed some combination of HTML and C# and the it’s rendered into an HTML in run-time and sent as HTML+Static Files. We will see some cool features later. For more on Razor Files:

Now add the following inside:

As you see, you can write your typical HTML Inside and it will be rendered as HTML. Now run it, and see what happens. We have our dear “Hello World” again 😊

This is all great, but now we want to be able to create and show complaints, that is our objective, so we will now turn to our Complaint MVC structure, starting by creating the Complaint Controller and its corresponding view.

Step 6. Starting with the complaint

So before continuing let’s create inside the Controllers folder a file named ComplaintController.cs, then create inside the Views folder a folder named Complaint and inside an archive named Create.cshtml. Your directory now should look like this:

Image for post
Image for post

Maybe you noticed that we are creating the view Create, that means that before our Index(The default action) we will be making the Create action first.

Next put this code inside your ComplaintController.cs

It’s simply creating the Controller object and telling the Create view to be rendered when the route matches.

The Complaint/Create view should render a form to write your complaint, let’s do it.

We will be using a cool feature from Razor Files called tag helpers, they are HTML-like elements made in .NET. To make the tag helpers we want available in all our views let’s create in the Views folder an archive named _Viewimports.cshtml, here we define all dependencies and Injections for all the views. So go inside Views and create a _Viewimports.cshtml file and put inside the following code:

the “@” symbol tells the Razor file that we are using C#, the @using yourComplaint is saying that we are in the yourComplaint namespace, and the @addTagHelper is telling the MVC Framework to load all Tag Helpers(what the * means) from Microsoft.AspNetCore.Mvc.TagHelpers .

With that out of the way, we can actually write our Create view, go to the Create.cshtml file we just created and add:

It seems like your typical form, with one exception, the asp-action that is available because it’s not your everyday HTML Form, but the Tag Helper Form which will be rendered in run-time according to our specifications. The asp-action is just a way of saying that the form should send its information to the Action “Index”. Since we are not specifying asp-controller the default controller it will be sent is the same which rendered it(In this case Complaint). Notice that we are using the get method, it’s just for the sake of this example we will be changing that further down the road.

Now press F5 and head to http://localhost:5000/Complaint/Create you should see:

Image for post
Image for post
The Complaint filling form

Just the form we were expecting, now, open the source code, you should see this

Well, see the HTML of the form that was rendered, your typical HTML form(Of course, otherwise your browser couldn’t have possibly rendered it), notice that the action is /Complaint. With help of our Tag Helper the MVC framework knew that to render the form with asp-action="Index" it just needed to make it action="/Complaint" since the default action is actually Index.

For a tutorial on form tag-helpers go here:

Now before we finish this step let’s fill the form and send it with the submit button, for example fill it like this:

Image for post
Image for post

When submitted, as expected, we get a white screen. But pay attention to the URL(Which we get to see since the form method is get) we get http://localhost:5000/Complaint?name=someName&mail=someMail&company=someCompany&complain=someComplain++++ ignore the ++++ in the last part, those are due to the textarea, pay attention instead to the composition /Complaint?name=someName&mail=someMail&company=someCompany&complain=someComplain. There is no second slash so it will automatically be routed to the action Index in the Complaint controller, yet we have things after a “?” that means we have arguments, great! The index will be called with the arguments name = “someName”, mail = “someMail”, company = “someCompany”, complain = “someComplain”. so with this knowledge, let’s go ahead and create the Index action and view.

Step 7. Creating the Index action and view

Okey now let’s add the Index action inside ComplaintController.cs, add the following lines inside the Complaint class:

Now your whole ComplaintController should be looking like this

Okay, what’s happening here? the Index arguments are what we talked about before, when we send the get method from the form the Index action gets called with the corresponding parameters. The ViewData is a dictionary provided by the MVC framework, which is shared with the view, so any information we want to give the view we can put it there. and then we return View(); which renders the view accordingly.

Now let’s create the view, you know how this go, inside the folder Views, inside the Complaint folder, create an archive named Index.cshtml.

Now let’s put the code inside Index.cshtml:

Yup, that’s all the code inside the Index view, The @ reefers to C# inside the Razor View, so it’s just calling that dictionary which was set in the controller.

This is all great, but before going to the next step let’s make one last change.

You see, it’s kind of weird that the form action is Index, actually the action should be Create, so let’s do that. We will change the form action for Create, but we will need to differentiate when the Create action is sending data or we just want to render the form. For that there are HTTP verbs, the data will be sent using post, and the form will be asked for using get, then the Create action will pass the data over to the Index action.

For routing using HTTP verbs we will use the token [HttpGet], when you put that on top of an action the MVC Framework knows that that particular action can only be matched with a GET verb. Let’s see this in action, modify your ComplaintController.cs to look like this:

So we added the [HttpGet] token on top of our old Create action, so now it will match with an incoming GET verb. So the second Create action will only match with a POST verb. The RedirectToAction works as expected, it returns the action Index and calls it with the object we created using new . So now when a POST request sent from the Form is sent to Create it is redirected into the Index, calling it with the arguments as expected(There’s a tidier way to do this with TempData, explore 😉 ).

Finally let’s modify our Create.cshtml function so that the form uses POST:

Now go, run the app, and test http://localhost:5000/Complaint/Create have fun. You now can submit the data and it will be visualized with the Index action.

For more on tokens and verbs:

Step 8. Adding a layout

I imagine that you are getting tired of rewriting the URL each time you want to go to the Complaint controller or Create action. So let’s add a layout for the whole page. We will use a cool ASP.NET Core feature that allows you to enclose a View inside another View, we will enclose all Views inside the same View.

For this we will first create an archive inside of the Views folder called _ViewStart.cshtml and we will create a folder called Shared inside the Views folder, inside we will create an archive named _Layout.cshtml.

Your directory now should look like this:

Image for post
Image for post

Now _ViewStart.cshtml is read before any other View, here we will tell ASP.NET that every View should use _Layout.cshtml as its Layout(It will be read from the Shared folder because it’s the folder shared by all Controllers and Views).

Inside _ViewStart.cshtml put :

Now inside the _Layout.cshtml add:

Notice that we added here the DOCTYPE, the HTML tag and the header that was so desperately missing from our previous HTML documents. Pay special attention to the line @RenderBody() this is were we are indicating that any other view should be rendered inside there.

Now you can run the example and explore it a little, but notice how we asked for a css file to style everything, so let’s tell ASP.NET to serve static files(Such as css) when requested.

In Startup.cs inside the Configure method, before the App.UseMvc line add

Now the app will look for static files inside the wwwroot(which is the path used by default).

Add inside wwwroot a folder called css, and inside, an archive called site.css and inside, put the following css code which I will not be explaining since it’s not the point of this guide.

Finally add a link on the Views\Complaint\Index.cshtml so that it renders a link to go to the create section.

And change the Views\Home\Index.cshtml so that it shows something a little more descriptive(Good bye “Hello World” you will always be in our hearts 😢)

Now let’s run our page! You will see something like this:

Image for post
Image for post

Navigate it for a while, you will see that before making any complaint the Complaints page will look weird saying “Your Name is and your mail is your complaint is about company and your complain is”. We will change this in a minute when we add our Model.

Step 9. Adding a Model

So for now we have been only working with with Controllers and Views, now we will add a Model, at this points most guides generates the controllers for the Model using Scaffolding, but we have done most of the work. We will only make the Create action, no edit nor delete action. We will be using an SQLite data base to keep track of all entries, this data base will be generated using Entity Framework’s Scaffolding.

Let’s get started!

First let’s create the Model folder at root level of the project, where MVC is defined to have all its models. Then inside the Model folder create an archive called Complaint.cs and another called ComplaintContext.cs. Now the directory should look like this:

Image for post
Image for post

In the Complaint.cs we should create the Complaint model, meaning what shape does the Data we are working with takes. We explicit this by means of a Complaint class, and putting inside of it each property a given complaint has and defining each pair of getters and setters for each of these properties. Our Complaint class is composed of: the Person’s name, the person’s mail, the company they are complaining about and what is the specific complain, plus an ID that uniquely identifies the particular Complaint which will be auto-generated by the database. Now open the Complaint.cs and put:

So not much magic going on here, just notice that it’s defined inside the namespace yourComplaint.Models because we will using that namespace a lot.

Next let’s write the code for the ComplaintContext.cs, you can think about this class like an interface that from which a model defines how it should behave when interacting with it, this kind of interface is called Container, and it can be instantiated(With certain previous steps). It inherits from DbContext which is an interface that actually makes a contract for the behaviors of a database, we will only define here what are the entities in the database that can be queried. Then in ConfigureService in the Startup.cs file, we will define which instance the interface actually takes when instantiating a ComplaintContext.

So inside Models\ComplaintContext.cs copy this:

Notice that we are using the Microsoft.EntitiyFrameworkCore namespace, the entity frameworks provides methods to work with relational data abstracting many SQL requests, for a more detailed introduction that uses Visual Studio:

The constructor is making use of the Dependency Injection pattern, this is used so that we can instantiate interfaces, I will not be going deeper with this. Also DbSet<tutorialWeb.Models.Complaint> is what is defining the relation of this context with our Model Complaint. For more info: It uses Visual Studio, still it’s a good read even if you don’t have it.

Let’s make sure our ComplaintContext is coupled with the correct SQLite behavior within Entity Framework. Remember how in ConfigureServices we defined the services available to our app, well let’s do it, let’s make ComplaintContext available to our Controllers through a Factory, also called Service, that is a method in charge of constructing our Container(Interfaces that should be instantiated through Dependency Injection, in this case ComplaintContext) so that is correctly coupled with the class we want. Then we will be able to Instantiate ComplaintContext, which will actually provide the correct instance that can handle SQLite requests within our model.

So head up to Startup.cs and add inside ConfigureService before Services.AddMvc(); :

options.UseSqlite("Data Source=yourComplaint.db"));

This should make the ConfigureServices look like:

This is making our Container ComplainContext available to the Configure method, and making it capable of interacting with a data base. We also need to add

using yourComplaint.Models;

On top of it all, so that everything we used can be found by the app.

Now the Startup.cs should look like:

Now, with this we are almost done injecting the DB service into our ComplaintContext container, we are just missing some configuration for our Data Base which will be looked for inside a file named appsetings.json, so create a file name appsetings.json in the root directory of your project, and copy and paste the following code(For more information on the configuration strings: )

Now we are missing the actual Data Base, let’s generate it using Entitiy Framework Scaffolding, that creates it based on our Model(Really cool, right?). For this we need to add another dependency to our yourComplaint.csproj file, just before the closing </project> add:

   <DotNetCliToolReference     Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /></ItemGroup>

Now your yourComplaint.cs should look:

Now go to your command prompt inside the root of your project and type

dotnet ef database update

First the migrations command will create a Data Base schema based on our model, then data base update will create an instance of this data base using SQLite, in fact, you will find a yourComplaint.db in your root directory, that’s your Data Base 🙂.(For more on migrations check:

Now we are almost done, with the web app, let’s run it so we know that everything is working a-okay. Is it? Great!

Step 10. Modifying the Controller and View behavior for our data

Now let’s revisit our Complaint Controller behavior, we want the Create[POST] action to actually not just pass on the values to the Index action, but to write them into the database, and then the Index should just grab all the values on the database and render the view based on them(We will use a table to present them).

This will actually not be hard, we already made the hard part. All the difficult behavior and communication with the database is handled in the backstage by the Entitiy Framework, we just use ComplaintContext to get the Data we want from the SQLite database.

Head up to Controllers\ComplaintController.cs and add the following lines on top of it all. Which are only the dependencies.

using yourComplaint.Models;

Then inside the Complaint class add

public Complaint(ComplaintContext context){_context = context;}

This is part of the Dependency Injection schema, what we are doing here is instantiating the container ComplaintContext(When actually we are instantiating the service provided).

Now change the old Create action for this new shiny one

Okay this one has a lot of new things, the async tells the function to work asynchronously, we want that since it will be doing I/O with the database, also instead of an IActionResult it returns a Task<IActionResult> which is some way of saying that someday it will return an IActionResult(We need this for the async behavior). The [Bind("ID,Name,Mail,Company,Complain)] tries to match our request to that of the schema based on our Complaint model, this creates a complaint object(in the scope of this method) as an instance of Complaint with the values sent to the server(supposedly from the Form), we add this complaint to the current _context and then we make _context save the current _context in the database. The await keyword is there so that this function only continues when this change is done, meanwhile the app keeps fulfilling other requests. Finally when the change is done, it redirects to the action Index .(For more on asynchronous methods on .NET Core: ).

Finally replace the Index action for this:

This action is asynchronous as well, it just render the view based on the model retrieved by the container _context when it is ready(Thanks to the await), this ToListAsync() retrieves all entries in our db in the shape of a list.

Now your controller should look like this:

Finally let’s modify the Complaint Index view so that it correctly displays every complaint.

Head up to Views\Complaint\Index.cshtml and change it completely for this:

This just creates a table with all the data we sent from the controller. Pay special attention to the @model on the top, this tells the View what Model we will be using. Then we display each of the Model’s labels, and see how we can use the foreach method inside a Razor file, displaying each of the items in our Model.

Then we are finish! At least with the web app. Go ahead, run the project. now you should see an empty table, click on the Create Complaint link, and create your complaint, maybe something like:

Image for post
Image for post

And now you should see:

Image for post
Image for post

And it works! Great, you did it! You created a MVC page with ASP.NET Core 2.0. Now drink your mandatory celebratory tea or coffee ☕ , take a breath or two and lets go ahead with the second part of this tutorial.

Image for post
Image for post
Lovely Docker Whale ❤ made with Legos ❤❤ Source:


Now you have your page, say you build it for deployment, you buy a small server to host your new fancy web page and in fact, deploy it. You find out that it doesn’t work there. Probably it’s just the .NET Core missing, or maybe it has another version? Or maybe you just added another dependency which conflicts with your other dependencies. With this simple web app probably there won’t be much problem just installing this .NET Core version, yet when the project grows in scale it gets more difficult to manage and less portable thus making it more prone to failure.

So how do we solve the problem of keeping track of all dependencies and installing them?

In the past we used Virtual Machines, Virtual machines are independent work environments with their independent OS, over this you mount your app. They are convenient, for they provide a way to port this VM(Virtual Machine) to another server or computer, but they are slow to initiate and sometimes installing a whole VM for a single APP is too much, and can there still be portability issues when deploying to the Cloud.

Comes Docker to save us, well, actually Containers. Docker just provides us a way to make and interact with Containers. Containers provides a way to encapsulate a program with all their dependencies, then they run on top, in this case, of Docker, which in turns run on top of the OS.

Take a look at this image to have a better idea of the differences between a VM and a Docker container:

Image for post
Image for post
While multiple containers each with its own app run on top of docker which in turn runs on top of an OS, each VM has its own OS with its own App while on top of docker multiple containers can be ran. Source:

So as you see you can even run multiple containers in a single docker installation. Each container has its own dependencies, and yeah you can then port that container to other machines, and if Docker is correctly installed it should run exactly the same, while porting a VM can be a real chore. Also, containers being faster to create and initialize can be incorporated to a development cycle much easier.

And each container is compartmentalized exposing only the ports and sockets you want. Making it more secure than running the app on top of the OS directly(Still not as secure as VMs but it can be made more secure by combining VMs and containers)

So to summarize, Docker’s containers are great because:

  • They improve cross-compatibility between environments
  • They improve security by exposing only what you want
  • They can be built for Linux or Windows very easily
  • They can be built like building blocks, a feature that we will talk more about later

And they have the following advantages over VMs:

  • Faster to run
  • Easier to set up
  • Improved portability
  • Consume less resources

If I didn’t convince you how awesome Containers are, this video probably will:

Now I will guide you through the installation and then I will teach you how to make a container of the web app we have already made. Then just to test it we will deploy it to Microsoft Azure.

Image for post
Image for post

Docker installation

Step 1. Click on this link: and download Docker for windows.

Step 2. Double click on the download file opening it.

Step 3. Accept Licensing following the wizard if needed.

Step 4. Wait for the wizard to download everything.

Image for post
Image for post

Step 5. Look for the app “Docker for Windows” in your PC and run it

Image for post
Image for post

Step 7. Wait for it to finish starting.

Image for post
Image for post

Step 8. Sing In or Create User in Docker cloud if you don’t have an account already(We will be using it).

That’s it! you should see the Whale logo in your task bar(Note: it could be hidden)

Thanks to this tutorial for providing the steps:

Image for post
Image for post

Some terminology before making our container

There is an important concept that we haven’t talked about yet, Images.

You can think of images as the blueprints and tools to build a container, it’s basically all the dependencies and archives needed to build the container, it’s immutable and many containers can be created from one image.

The cool thing about images is that you can build an image from another image and that image from another image or even from many different images, like stacking Legos(Analogy that I stole from the video shown previously in this article).

Image for post
Image for post
Stacking books just like stacking Images.

For more details on images and containers and their differences:

Building our container

Step 1. Before anything, check that your Docker installation is working correctly. Open a Command prompt and type docker version you should see something like:

and more information.

Note: If it says that the command is not recognized try rebooting your PC.

Step 2. Now we want to build our Image to build the container, for this we have to tell docker how to build the image, so add the file Dockerfile to the root of your project. This file is like a recipe for docker to build your image, just a series of steps to follow.

Here is the code for the file:

Let’s start by the first line, the FROM is saying that we will be building our image on top of the image aspnetcore-build:2.0, these are the dependencies necessary to create an ASP.NET Core 2.0 project. you might be wondering how we are addressing this image if we never created it. Docker just knows that if it can’t find it in your local images it will try to pull it from an image public repository(Of which we will be talking later on). Also this creates an environment over which we will be working.

Then the WORKDIR APP tells docker that we will be working on the directory APP, and since it doesn’t exist it creates it. Then we copy the archive with the needed dependencies from our actual directory to the working directory(app), and with this file and the ASP.NET image we build our dependencies with the restorecommand (Note that we can use dotnet commands thanks to the ASP.NET image).

We then copy everything else from the folder to the app directory. Then we build the project for release and we build our data base.

Finally we create another environment that we will use for deployment, which is a much leaner version of the ASP.NET Core 2.0 only for deployment. We copy our release folder to this new environment, we have to do this since each environment is like its own compartment. And now we just tell docker that when we run our app, it starts by running dotnet yourComplaint.dll which is the way to run the app when it’s in the deployment stage.

Image for post
Image for post
The flow of the archives within Docker. Note that the steps refer to the order of the particular steps shown on the image not of the overall process.

Step 3. Create a .dockerignore file in your root folder. This one is similar to a gitignore file, just tells Docker what to ignore when building the image, which will be the obj folder, the bin folder and the yourComplaint.db since we will create the dependencies and the data base in the process of building the image(To have a clean database and so that each container will have its independent clean database).

Step 4. Go to your command prompt and type: docker build -t yourcomplaint . this will build our image, it can take a while since it has to download other images from the cloud.

Now you can run docker images and you will see our yourcomplaint image among others which were needed to build our image on top.

Step 5. Run the command docker run -d -p 8000:80 yourcomplaint this will create a container from the image your complaint, the “-d” says it will run in the background and the “-p 8000:80” will expose the internal docker port to our PC’s port 8000. Remember that we had to explicitly expose each resource we wanted from a docker container(Also, the ASP.NET Core application naturally exposes port 80 when on Release).

Now check docker ps which will show all the containers running on this docker instance, notice the Ports:>80/tcp this just means that it’s exposing its port 80 to our PC’s port 8000, now go ahead to http:\\localhost:8000 and you should see our page. To remove the container use docker stop <container ID> or docker stop <container name> which just stops the container and the docker rm <container ID or name> removes it you could also run docker rm -f <container ID or name> to stop and remove. Notice that you could start many instances linked to different ports.

So yeah, congratulations! you just have built your image and container, we are on the final stretch.

Image for post
Image for post

Deploying to Microsoft Azure Cloud

Now we will deploy our web to the cloud using Microsoft Azure, to do that easily, we will need to upload our image to the Docker Cloud registry. A registry is, simply put, an SVN for images, Docker cloud is a free public one which docker will use by default, you can make your own private one or use others’.

So do the following:

Step 6. Run docker login and login with the account you made previously.

Step 7. Tag the image using docker tag yourcomplaint <yourusername>/complaintrepository:first the “:” just says that after it will be the tag of the image, in this case first. Tags are just a way of versioning our images, complaintrepository indicates a repository where you could put many images, you could also use another name.

Step 8. Run docker push <your username>/complaintrepository:first this will push the repository to the cloud, wait until it’s finished

Now we have our image in the cloud, now we just need to upload it to Microsoft Azure.

Microsoft Azure is a collection of cloud services, among which is a way to host docker containers.

Step 9. Go to and sign up with a free account for azure services, you might need to input your credit card information but don’t worry it won’t bill you unless you explicitly accept it.

Step 10. Go to and login with your account, here you have access to all the cool tools azure offers you within an intuitive interface. When you go in, you will see something like this:

Image for post
Image for post

Step 11. Go to the + New on the left top corner, then to Web+App and select Web app for containers

Image for post
Image for post

Step 12. Enter your desired app name, select free subscription, then click on Configure Container select Image Source: Docker Hub, Repository Access: Public And image and optional tag: <your Docker Hub username>/complaintrepository:first . Also on the bottom click on pin to dashboard.

Image for post
Image for post
I’ve already taken the yourComplaint name 😜.

Step 13. Navigate to <yourappname> and visit your very own webpage.

Step 14. Celebrate!

Image for post
Image for post


You did it! you made your very own ASP.NET Core 2.0 MVC Page, dockerized it and deployed it on Microsoft Azure Services.

You’ve learned a lot, at least I hope so, you now know how to create an MVC Page using ASP.NET Core, how to create a Controller, an Action and a View using Razor Files and a simple Model and how to use Entity Framework to generate and interact with a data base in SQLite.

You have also learned how to create a Docker image, a Docker container, and even how to deploy it on to Microsoft Azure.

So this project was pretty simple, you need to add authentication and data validation and probably some JavaScript to make it more viable. But with ASP.NET Core it’s as simple as this project, and using code scaffolding and some templates it can be even easier and faster. The important thing is that you grasped the basics, and with just a little more you can build many more complex pages. And .NET Core + Docker make this portable, and compatible with many platforms, so yeah all these tools are pretty useful.

Now what comes next?

Well next, you could try and add some JavaScript functionality, remember that any static file goes into wwwroot. Then, you could also add some edit and delete for each entry, you will need the command _context.complaint.SingleOrDefaultToAsync(m => == id) and _context.Update and _context.complaint.Remove , but all these can be generated with code scaffolding so head to this tutorial: to learn more about that.

Also this page could’ve been done with a cool new feature of ASP.NET Core 2.0 called Razor Pages, which is a way to manipulate pages using the model and skipping the Controller. So head up to this tutorial to learn more about that:

Also with docker, you could have set up swarms, that is a way to run many instances of the container working together, with that you should also learn how to use a volume for the data base which is a way to have your data be persistent separated from the containers. For a tutorial with an introduction to both topics using python head up to:

And that will be all, I’m glad you took the time to read this. Please leave your feedback and share if you liked it. I hope you have fun programming! 😊

Image for post
Image for post
Farewell fellow coder

Extra notes:

Docker Container OS

We have used docker in Linux mode which is the default, that is why we could deploy it to a Linux server afterwards, to switch to windows mode and make the container run natively on Windows you can go to the docker symbol on your task bar, right click, and click on “Switch to windows containers”

Image for post
Image for post
Switching to windows containers…

Differences between ASP.NET Core 1.x and ASP.NET Core 2.0 for our project:

We made all this using ASP.NET Core 2.0, but we didn’t almost any new feature. It just simplified a little the syntax.

For ASP.NET Core 1.x we needed to specifically configure the server in our entry point.

Instead of this we used:

This pattern is needed for the EF(Entitiy Framework) Scaffolding to work.

And loading appsetings.json for the db configuration was automatic in our ASP.NET Core 2.0 project, in 1.x it wasn’t and we would have needed to add

Other changes were the obvious version dependent dependencies that should have been changed in yourComplaint.csproj . And to use Razor Files we would have to explicitly enable it.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store