.Net 6 runs on Linux and that allows us to create a dev container without any hassle. Let’s look what we need to run a minimalistic API project inside a dev container and connect it to the SQL Server we created last week.
The minimalistic API project
Part of .Net 6 is the minimal API template in which our whole application fits into a single Program.cs file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
using Dapper; using System.Data.SqlClient; using Microsoft.Extensions.Configuration; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); var config = app.Services.GetRequiredService<IConfiguration>(); var connectionString = config.GetConnectionString("Adventure"); var sqlCon = new SqlConnection(connectionString); var emplyeeHandler = new EmployeeHandler(sqlCon); app.MapGet("/", () => "Welcome!"); app.MapGet("/employee/{id}", (int id) => emplyeeHandler.FindById(id)); app.Run("http://+:7000"); class EmployeeHandler { private readonly SqlConnection connection; public EmployeeHandler(SqlConnection connection) { this.connection = connection; } public Person FindById(int id) { var query = @"SELECT [BusinessEntityID] AS [Id] ,[FirstName] ,[LastName] ,[ModifiedDate] FROM [AdventureWorks2019].[Person].[Person] WHERE BusinessEntityID = @id"; var result = connection.Query<Person>(query, new { id }).First(); return result; } } public record Person(int Id, string FirstName, string LastName, DateTime ModifiedDate); |
The + in http://+:7000 is important. Without that you cannot connect to your application when you run it inside a container.
The connection string is in the appsettings.json, where we can use the name of the SQL Server container as the host name. Be aware that we need to connect to port 1433 (the internal port in the container) and not to port 6000 (the port that Docker gives us to connect from SSMS into the container database) when we connect from container to container:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "Adventure": "Data Source=db,1433;Initial Catalog=AdventureWorks2019;User Id=sa;Password=P@ssword123;" } } |
Create a docker-compose.yaml file
The .Net SDK Docker image from Microsoft offers everything we need to develop our application. Therefore, we can once more skip the part of creating our own Dockerfile and directly jump to the docker-compose.yaml file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
version: "3.2" services: db: image: mcr.microsoft.com/mssql/server:latest volumes: - ./container_db:/var/opt/mssql/data environment: ACCEPT_EULA: Y SA_PASSWORD: P@ssword123 ports: - 6000:1433 api: image: mcr.microsoft.com/dotnet/sdk:6.0 volumes: - ./MinApi:/workspace working_dir: /workspace command: sh -c 'while true; do sleep 30; done' ports: - 7001:7000 depends_on: - db |
I extended the docker-compose.yaml file for SQL Server 2019 and added a section for the API application. The depends_on entry ensures that the API container only starts after the SQL Server container is ready.
The start command for the container must be something else than dotnet run. We want to change our code and rebuild our application, something that is not possible if the starting command blocks our files. Instead, we use the same endless sleep cycle as we did with the Ruby container.
Start SQL Server and the API
As with all other dev containers we can run this single command to start SQL Server first and then our API container:
1 |
docker-compose up |
Run the API
We can now connect to the API container and run the SDK command to compile and run our application:
1 |
dotnet run |
Test the API
To see if everything works we can use our browser or HTTPie and query our API:
1 |
http localhost:7001/employee/33 |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Tue, 23 Nov 2021 21:22:34 GMT
Server: Kestrel
Transfer-Encoding: chunked{
“firstName”: “Annik”,
“id”: 33,
“lastName”: “Stahl”,
“modifiedDate”: “2008-12-10T00:00:00”
}
Add features to the API
We can connect VS Code to our dev container and add new features as we seam fit. Whenever we want to recompile we need to kill the current dotnet run process and run it again:
1 |
dotnet run |
.Net 7
Getting .Net 6 into a dev container was not much work. Even better, when in a few weeks the first images for .Net 7 arrive, we only need to change one line in our docker-compose.yaml to check if our application works with the newest version of .Net. Benefits like this are another reason to spend some time with dev containers.
Next
On Friday we explore the steps to put a Python application into a dev container. There are a few points to be aware of or else it will take a long time to create your container.