Click here to Skip to main content
13,630,357 members
Click here to Skip to main content
Add your own
alternative version

Stats

8.4K views
34 downloads
10 bookmarked
Posted 2 Jan 2018
Licenced CPOL

Exploring ASP.NET Core 2.0 and Docker on MacOS

Rate this:
Please Sign up or sign in to vote.
A quick walk-through on building an ASP.NET Core 2.0 application on MAC and running it on Docker container.

Introduction

Last year, I wrote an article about “.NET Core On Mac - Building An ASP.NET Core App With Web API, EF, PostgreSQL And Running It On Docker”. The article was using .NET Core 1.1 version and If you’ve been following the same steps mentioned from the article using .NET Core/ ASP.NET Core 2.0, then it’s expected that the steps won’t work anymore.

Over a year, there has been some changes from .NET Core 1.x to version 2.0. In this article, we’ll explore ASP.NET Core 2.0 and Docker by building a simple Web API application and deploying it on a Docker container.

Quote:

Note: Before you move down further, make sure that you have a basic understanding on ASP.NET Core and Docker because I will not talk about the details about each technology in this article.

Prerequisites

Before getting our hands dirty, we’ll need to update/install the required tools and SDKs for us to build and run the application in MAC environment. Go ahead and install the following:

Docker Images for .NETCore 2.0 and ASP.NET Core 2.0

Once you have installed all the prerequisites, we need to pull the required docker images for both .NET Core and ASP.NET Core from Docker Hub. Go ahead and open the terminal and run the following command separately:

  • docker pull microsoft/dotnet:2.0.0-sdk
  • docker pull microsoft/aspnetcore:2.0.0
  • docker pull microsoft/aspnetcore-build:2.0.0

After pulling the docker images, you can verify it by running the following command:

$ docker images

The command above should result to something like this:

Figure 1:Docker Images

Creating Your First ASP.NET Core 2.0 Project

Now, fire up Visual Studio 2017 and create an empty ASP.NET Core project just like in the figure below.

Figure 2: New ASP.NET Core 2 Empty Project

Click “Next”. On the next screen, select .NET Core 2.0 as target framework and then click “Next”. It should now bring you to the following screen:

Figure 3: Configure ASP.NET Core Project

For the simplicity of this demo, just name the project as “aspnetcoredemo” and then browse the location to where you would want the project to be created. Click “Create” to let Visual Studio generate the default files for you. You should be able to see something like this:

Figure 4: The Generated Files

Running the Project for the First Time

Click the "Play" button to build and run the project. When everything builds successfully, it should display something like this in your browser:

That’s it! We now have an ASP.NET Core 2.0 app running on MAC.

Let’s Get Going!

Now, to make this demo more exciting, we will move a bit further and create a simple Web API that handles a basic CRUD operations and use Posgres as our database. We will then run our application and database inside a Docker container.

Adding a Docker File

The first thing we need is to create a Docker in our project. The Dockerfile contains the instruction to build the docker image. For more information, see: Dockerfile Reference

Add the following command within the Dockerfile:

FROM microsoft/aspnetcore-build:2.0.0 AS build

WORKDIR /code

COPY . .

RUN dotnet restore

RUN dotnet publish --output /output --configuration Release

FROM microsoft/aspnetcore:2.0.0

COPY --from=build /output /app

WORKDIR /app  
ENTRYPOINT ["dotnet", "aspnetcoredemo.dll"]

Integrating EF Core and PostgreSql

Switch back to Visual Studio and install the latest Nuget packages below:

  • Npgsql.EntityFrameworkCore.PostgreSQL
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.Design

The packages above enable us to use EntityFramework Core as our data access mechanism. We’ll be using EF Core to sync and update database from PosgreSql database and then use Web API to serve data requests.

Entity Framework Core now supports a variety of database providers. In this particular demo, we will integrate PostgreSQL in our .NET Core application.The easiest way to install Postgres is using Homebrew which should be included upon installing the .NET Core SDK. Now run the following command to download and install PostreSQL:

$ brew install postgresql

If the installation goes well, then the database manager should be installed. Now, let's launch the PostgreSQL service container by running the following command:

$ docker run -d --name localdb -e POSTGRES_PASSWORD=supersecret postgres

The -d option runs a container in the background and prints the container ID. The --name assigns a name to the container, in this case we named our container as "localdb". The -e allow us to set the environment variables, which in this case, we’ve set a password to "supersecret" for our Postgres image using the POSTGRES_PASSWORDvariable.

Running the command above will expose the postgres port 5432 which allow a standard container to be available to the linked containers. The initdb will also be generated with default user and database.

To verify that our PostgresSQL Docker container is up and running, do:

$ docker ps

To test the connection, you can do:

$ docker run -it --rm --link pg-db:postgres postgres psql -h postgres -U postgres 

Creating the Application

Now that we have our database ready inside a docker container, it’s time for us to build the application.

Setting Up a Database ConnectionString

Add a new empty .jsonfile and then name the file as “appsettings” just like in the figure below:

Figure 6: Add New File

then copy the following setting below:

"DbContextSettings": {
    "ConnectionString": "User ID=postgres;Password=supersecret;Server=postgres;Port=5432;Database=POSTGRES_USER;Integrated Security=true;Pooling=true;"
}

The connectionstring above will allow us to connect to the PostgreSql service container that we ran earlier.

Creating a Model

For this demo we will be using EF Code-First approach which means, we will create the Model first and then run a migration to let EF generate the database/schema based on our Model.

Create a new class at the root of your project and name the file as “Student”. Copy the following code below:

namespace aspnetcoredemo  
{
    public class Student
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

Defining a DbContext

EF Core Code-First development approach require us to define a data access context class that inherits from the DbContext class. Now, let’s add a new class at the root of our project. Name the file as “StudentContext” and then copy the following code below:

using System;  
using Microsoft.EntityFrameworkCore;

namespace aspnetcoredemo  
{
    public class StudentContext: DbContext
    {
        public StudentContext
        (DbContextOptions<StudentContext> options)  
            : base(options)  
        { }

        public DbSet<Student> Students { get; set; }
    }
}

Registering Services with Dependency Injection

Next thing that we need is to register the DbContext as a service and enable MVCservice to enable Web API. Open startup.cs and replace the existing code with the following:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.AspNetCore.Http;  
using Microsoft.EntityFrameworkCore;  
using Microsoft.Extensions.Configuration;  
using Microsoft.Extensions.DependencyInjection;

namespace aspnetcoredemo  
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName} .json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            var connectionString = Configuration["DbContextSettings:ConnectionString"];
            services.AddDbContext<StudentContext>(opts => opts.UseNpgsql(connectionString));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();

        }
    }
}

Let’s modify the Program.cs to create a database on startup. Here’s the full code below:

using System;  
using Microsoft.AspNetCore;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.EntityFrameworkCore;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Logging;

namespace aspnetcoredemo  
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();

            var host = BuildWebHost(args);

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    services.GetService<StudentContext>().Database.Migrate();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }

            host.Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

EF Core does not do the migration automatically, that’s why we need the pieces of configuration above for us to use Code-First migrations. The Database.Migrate()method piece is responsible for two things: (1) The creation of database in PostgreSQL if it does not exist yet. (2) Migrating the database schemas to the latest version.

Adding Migrations

We will be using EF Core tools to scaffold our migration and updating the database. We’ll be using the command line (dotnet CLI) to run our migrations. We can’t add the Microsoft.EntityFrameworkCore.Tools.DotNet package from Nuget as of this time of writing because of this error:

“Package 'Microsoft.EntityFrameworkCore.Tools.DotNet 2.0.0' has a package type 'DotnetCliTool' that is not supported by project”

As a workaround, we can edit the project file (.csproj) and add the following configuration below:

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

Now open the terminal to the location where your project root is located and then do:

$ dotnet ef migrations add InitialMigration

The ef migration add is the command to add migrations. When the migration is successful, you should be able to see a new folder named "Migrations" that contains the migration files as shown in the figure below.

Figure 7: Migration Files

The files generated above will be used to create the database on initial run.

Creating a Web API Controller

It’s time for us to create a simple Web API methods to work with simple GET and POST requests. Add a new Web API Controller class and copy the following code:

using System.Collections.Generic;  
using System.Linq;  
using Microsoft.AspNetCore.Mvc;

namespace aspnetcoredemo.API  
{
    [Route("api/[controller]")]
    public class StudentsController : Controller
    {
        private readonly StudentContext _context; 

        public StudentsController(StudentContext context)
        {
            _context = context;
        }

        // GET: api/students  
        public IEnumerable<Student> Get()  
        {  
            return _context.Students.ToList();  
        }  

        // GET api/students/1  
        [HttpGet("{id}")]  
        public Student Get(int id)  
        {  
            return _context.Students.FirstOrDefault(x => x.Id == id);  
        }  

        // POST api/students  
        [HttpPost]  
        public IActionResult Post([FromBody]Student value)  
        {  
            _context.Students.Add(value);  
            _context.SaveChanges();  
            return StatusCode(201, value);  
        }  

    }
}

Nothing really fancy there, the code above just contains a few basic methods that communicates to StudentContext. Notice that we’ve injected an instance of our StudentContext in the Controller’s constructor, so we can interact with our database, and use the it for querying the data.

Running the Application on Docker

At this point, we are ready to deploy the application on Docker. First let’s build the app by running the following command:

$ docker build -t dockerdemo .

The command above will generate a new instance of image within our docker machine. You can check the list of image by running docker images in the command line.

Now, run the following command to ensure that our PostgreSQL database image is up and running:

$ docker ps 

Now, let’s run our ASP.NET Core 2.0 application and link the database that we’ve created using the following command:

$ docker run -it -p 5000:80 --link localdb:postgres dockerdemo

Testing the Web API Endpoints

Here are some of the screenshots of the Endpoint test results, using Postman.

POST 

Figure 8: Output

GET 

Figure 9: Output

GET/Id 

Figure 10: Output

That's it! I hope you will find this article useful.

References

Summary

In this article, we’ve learned the basics on setting up .NET Core 2 on MAC environment and learned how to create a simple ASP.NET Core 2 application with Web API, EF, PostgreSQL and running it on Docker.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Vincent Maverick Durano
Technical Lead
Philippines Philippines
A code monkey who loves to drink beer, play guitar and listen to music.

My exploration into programming began at the age of 15;Turbo PASCAL, C, C++, JAVA, VB6, Action Scripts and a variety of other equally obscure acronyms, mainly as a hobby. After several detours, I am here today on the VB.NET to C# channel. I now work on ASP.NET+C#+MSSQL+EF+Angular+JavaScripts+AJAX+Xamarin, which go together like coffee crumble ice cream.

9-time Microsoft MVP, 3-time C# Corner MVP, CodeProject MVP, Microsoft Influencer, Dzone MVB and a regular contributor at CodeAsp.Net in which I also moderate, C# Corner, AspSnippets, Xamarin but more often at the official Microsoft ASP.NET community site where I became one of the All-Time Top Answerer with ALL-STAR recognition level (the highest attainable level with 100,000+ points).

My main interests include technologies, travel, beaches, mountains, paintings, arts, supernatural, ghosts, angels, vampires, mythology, mysteries, para-sciences , scifi ,music, guitar, cars and motorbikes.

You may also be interested in...

Pro

Comments and Discussions

 
QuestionMSBUILD Broken... Pin
Jeremy Stafford 15-Jan-18 15:27
memberJeremy Stafford 15-Jan-18 15:27 
AnswerRe: MSBUILD Broken... Pin
Vincent Maverick Durano8-Jan-18 15:36
professionalVincent Maverick Durano8-Jan-18 15:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web03-2016 | 2.8.180712.1 | Last Updated 3 Jan 2018
Article Copyright 2018 by Vincent Maverick Durano
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid