Вы находитесь на странице: 1из 7

16/03/2019 Running ASP.

NET Web API Solution in Docker - CodeProject

Running ASP.NET Web API Solution in Docker


Gunnar S, 6 Mar 2019

This article describes how to containerize an ASP.NET WebApi solution with Visual Studio, how to pass data via environment
variables and also how to run the images in docker without Visual Studio.

Download code from Github

Introduction
The tricky part when running a web solution with a web API in docker containers is to map the URLs and ports so that the code
running inside the docker container can be accessed from outside. This is a question of docker configuration and minor code
changes.

Background
This article is a contribution to the Docker Contest described in this article.

Prerequisites
Visual Studio 2017, community version. Latest release.
You have installed “Docker For Windows” on your computer: https://download.docker.com/win/stable/Docker for Windows
Installer.exe.
You have an existing solution with a web API and a web “model-view-controller“ project and the MVC project is able to
communicate with the web API via a REST http interface. If not, you may use the CarApi and CarClient projects (see
below) to implement your own solution.

The code belonging to this article is the containerized versions of CarClient and CarApi from this article.

In this article, docker support has been added and the docker configuration files have been updated to make it possible to access
the API from CarClient, both frontend and backend.

How to Containerize an Existing Project


To add docker support for an existing web project, e.g., CarApi, open the project in Visual Studio, right click the project and chose
Add -> Docker Support:

https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 1/7
16/03/2019 Running ASP.NET Web API Solution in Docker - CodeProject

A docker configuration file, “Dockerfile”, is created and it looks like this:

# For more info see: http://aka.ms/VSContainerToolingDockerfiles


FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/aspnetcore-build:2.0 AS builder


WORKDIR /src
COPY *.sln ./
COPY CarApi/CarApi.csproj CarApi/
RUN dotnet restore
COPY . .
WORKDIR /src/CarApi
RUN dotnet build -c Release -o /app

FROM builder AS publish


RUN dotnet publish -c Release -o /app

FROM base AS production


WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "CarApi.dll"

Do this for both projects in your existing solution, i.e., for the web API and the web MVC project. When this is done, you need to
add a docker-compose project to your solution.

Add a docker-compose Project


To add a docker-compose project to the solution, right click one of the projects and select Add -> Container Orchestrator
Support -> Docker Compose -> Target OS:Linux.

https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 2/7
16/03/2019 Running ASP.NET Web API Solution in Docker - CodeProject

The added project is of type “.dcproj” and the following files are created:

The next step is to right click the other project and in the same way, select Add -> Container Orchestrator Support ->Docker
Compose -> Target OS:Linux.

Suppose that your two projects are called “CarClient” and “CarApi”, then the resulting docker-compose.yml looks like this:

version: '3.4'

services:
web:
image: ${DOCKER_REGISTRY}carclient
build:
context: .
dockerfile: CarClient/Dockerfile

api:
image: ${DOCKER_REGISTRY}carapi
build:
context: .
dockerfile: CarApi/Dockerfile

The Containerized Solution with docker-compose


After having added Dockerfiles to each project and the docker-compose project to the solution, the solution consists of three
projects: A web MVC project, a web API project and a docker-compose project.

Add Environment Variable


To make the containerized version function, we need to make some configuration changes.

Backend
In the original CarClient project, the web API was reached via the following URL:
https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 3/7
16/03/2019 Running ASP.NET Web API Solution in Docker - CodeProject

private static readonly Uri Endpoint = new Uri("http://localhost:54411/");

Here, the URL is hard coded but we could also define an environment variable in launchSettings.json:

"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"CarApiUrl": "http//localhost:54411/"
}

The environment variable is read like this:

var carApiUrl = Environment.GetEnvironmentVariable("CarApiUrl");

For the containerized solution, we use “dns discovery”. Docker networking, as well as kubernetes handles all this magic. Instead of
localhost, the name of the service, as defined in the docker-compose, is used. To call the CarApi, use http://carapi. You don’t
need to set the port number as the port number is an external attribute.

We will use the environment variable called CarApiUrl. This variable is defined in the docker-compose.yml file like this:

version: '3.4'

services:
...
carclient:
image: ${DOCKER_REGISTRY}carclient
environment:
- CarApiUrl=http://carapi/
build:
context: .
dockerfile: CarClient/Dockerfile

The environment variable is read in file Utils.cs:

private static readonly Uri Endpoint = new Uri(Environment.GetEnvironmentVariable("CarApiUrl"));

By using an environment variable, we don't need to change the code, only the configuration, when containerizing the solution.

Frontend
The JavaScript running in the browser uses port 54411. We must expose port 54411 by changing the docker configuration file for
CarApi like this:
In the web API Dockerfile, write EXPOSE 54411:

# For more info see: http://aka.ms/VSContainerToolingDockerfiles


FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 54411
...

In the docker-compose.yml, map external port 54411 to internal 80:

version: '3.4'

services:
carapi:
image: ${DOCKER_REGISTRY}carapi
ports:
- 54411:80
...

https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 4/7
16/03/2019 Running ASP.NET Web API Solution in Docker - CodeProject

The original JavaScript code is kept:

xmlhttp.open("GET", "http://localhost:54411/api/car", true);

That’s all that's needed. You can now run your containerized solution in Visual Studio.

Run Your App without Visual Studio


Rebuild your solution with Visual Studio with the Release configuration. Run the docker-compose project with F5 to ensure the
images are updated.

Outside of Visual Studio, you’ll need to use the docker-compose command rather than docker run. In PowerShell, cd to the
solution folder where docker-compose.yml is located. Then run the docker-compose command like this:

…> docker-compose --no-ansi up -d --force-recreate --remove-orphans

Then check with docker ps on which port carclient is running:

…> docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …

5c5c3a6fa376 carclient "dotnet CarClient.dll" 12 hours ago Up 12 hours 0.0.0.0:32781->80/tcp

20cf31344091 carapi "dotnet CarApi.dll" 12 hours ago Up 12 hours 54411/tcp, ….

Carclient runs on port 32781. The app will then become accessible at http://localhost:32781.

Explanation
If the Debug configuration is set, then empty non-workable images are created by Visual Studio. It manually maps the empty
container to the filesystem to make possible debugging, "Edit and Continue" features and so on. Therefore, dev image is useless
without Visual Studio. Build the image in the Release configuration to make it usable.

The full publishing process is described in the documentation: Visual Studio Tools for Docker.

Run Your App with Docker Networking


It’s possible to make containers communicate via docker networking without YAML.

First some useful docker commands:

Kill all, (start, run, rm all)

>>docker kill $(docker ps -aq)

Start shell inside container

>>docker exec -i -t container_name /bin/bash

Run the solution without docker-compose but with docker networking

cd to carapi

>>docker build -t carapi .

>>docker run -e ASPNETCORE_ENVIRONMENT=Development -d -p 54411:80 --name carapi carapi

Inspect the docker bridge network to find the IP address used by carapi;

https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 5/7
16/03/2019 Running ASP.NET Web API Solution in Docker - CodeProject

>> docker network inspect bridge


[
{
"Name": "bridge",
"Id": "fce049eb23e5fb1a7b5c801a082d8809efd4d369f18de4693b35e6524f1d55c0",
"Created": "2019-03-04T15:13:40.1528498Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"cbf2ae63374659b4a9c8e341e22b20a7f3e6d7b6593d289d7ffa4db415d6e8b6": {
"Name": "carapi",
"EndpointID": "0c25cdaa8403c928b12efc1e5f6bb40b71e76acc438f8b95d2ba7a135eb333e9",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"f1abe1fdb72a23b61f7160aa49aca06f9c849dd3fca9432257168175625589a2": {
"Name": "carclient",
"EndpointID": "aa4dd99b8045e5a0c77f6dadd17ad9d3579c82c3cf7ee2af45461e6284523739",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]

You see that carapi is using IP: 172.17.0.3. Use this ip number for the environment variable CarApiUrl in the docker run
command below:

cd to carclient

>>docker build -t carclient .

>>docker run -e ASPNETCORE_ENVIRONMENT=Development


-e CarApiUrl=http://172.17.0.3 -d -p 8080:80 --name carclient carclient

Then start client in a browser with localhost:8080.

Now the containers communicate without YAML using the docker bridge network.

Points of Interest
https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 6/7
16/03/2019 Running ASP.NET Web API Solution in Docker - CodeProject

In this article, we've discussed how to containerize an ASP.NET WebApi solution with Visual Studio, how to pass data via
environment variables and also how to run the images in docker without Visual Studio. We also see how to use docker networking
as an alternative to docker-compose and YAML files.

History
August 24, 2018 - The first revision of this article was published
September 1, 2018 - Environment variable was introduced
September 6, 2018 - Run the app without Visual Studio
March 6, 2019 - Run app with docker networking without docker-compose

The code is available here.

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

About the Author


Gunnar S
Software Developer (Senior)
Sweden

I work as Senior Developer mainly in Microsoft environment and my strenghts are SQL, C# and ReactJS.

Comments and Discussions


8 messages have been posted for this article Visit https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-
API-Solution-in-Docker to post and view comments on this article, or click here to get a print view with messages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile Article Copyright 2018 by Gunnar S
Web04 | 2.8.190306.1 | Last Updated 7 Mar 2019 Everything else Copyright © CodeProject, 1999-2019

https://www.codeproject.com/Articles/1257705/Running-ASP-NET-Web-API-Solution-in-Docker?display=Print 7/7