·
Todos os posts
dotnetdockergithub

CI/CD in Github Actions for .NET 5 applications with Docker

Setting up CI/CD in Github Actions for .NET 5 applications with Docker.

We know how many benefits come with implementing CI/CD and continuous integration in projects, and how much it improves delivery quality.

In this article you will see how to implement some CI/CD steps in Github Actions using .NET 5. You will find that the basic implementation is quite straightforward — but don't stop here, there are many other flows you can build beyond these.

1. Structuring the Project

We will create a simple WebApi that displays some color data. We will also add a test project using XUnit, which we will use as one of the CI/CD flows.

1.1. Creating the Solution

dotnet new sln -n Colors

1.2. Adding the WebApi

dotnet new webapi -n Colors.WebApi

1.3. Adding the Test Project

dotnet new xunit -n Colors.Tests

1.4. Adding projects to the solution

dotnet sln add .\Colors.WebApi\Colors.WebApi.csproj
dotnet sln add .\Colors.Tests\Colors.Tests.csproj

1.5. Restoring the project

dotnet restore
dotnet build Colors.sln

2. WebApi Implementation

I implemented a simple API with a color repository that handles GET requests and returns colors, along with some basic tests. The project structure looks like this:

2.1. ColorController

ColorController.cs
using System.Linq;
using Colors.WebApi.Repositories;
using Microsoft.AspNetCore.Mvc;
 
namespace Colors.WebApi.Controllers
{
    [ApiController]
    [Route("api/colors")]
    public class ColorController : ControllerBase
    {
        [HttpGet]
        public IActionResult GetAllColors()
        {
            var colors = ColorsRepository.Get();
            return Ok(colors);
        }
        [HttpGet("{name}")]
        public IActionResult GetByName(string name)
        {
            var colors = ColorsRepository.Get();
            var response = colors.Where(x => 
                     x.Name.ToLower() == name.ToLower())
                     .FirstOrDefault();
            return Ok(response);
        }
    }
}

2.2. Color Model

Color.cs
namespace Colors.WebApi.Models
{
    public class Color
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

2.3. Repository — ColorRepository

ColorRepository.cs
using System.Collections.Generic;
using Colors.WebApi.Models;
 
namespace Colors.WebApi.Repositories
{
    public static class ColorsRepository
    {
        public static List<Color> Get()
        {
            var colors = new List<Color>();
            colors.Add(new Color { Id = 1, Name = "Red" });
            colors.Add(new Color { Id = 2, Name = "Black" });
            colors.Add(new Color { Id = 3, Name = "Pink" });
            colors.Add(new Color { Id = 4, Name = "Green" });
            colors.Add(new Color { Id = 5, Name = "Gray" });
            return colors;
        }
    }
}

2.4. Test — ColorControllerTest

ColorControllerTest.cs
using System.Collections.Generic;
using Colors.WebApi.Controllers;
using Colors.WebApi.Models;
using Microsoft.AspNetCore.Mvc;
using Xunit;
 
namespace Colors.Tests
{
    public class ColorControllerTest
    {
        private ColorController _controller;
       public ColorControllerTest()
        {
            _controller = new ColorController();
        }
        [Fact]
        public void GetAllColorsTest()
        {
            var response = _controller.GetAllColors() 
                                             as OkObjectResult;
            var colors = response.Value as List<Color>;
            Assert.NotNull(colors);
        }
        [Theory]
        [InlineData("red")]
        [InlineData("black")]
        public void GetColorTest(string color)
        {
           var response = _controller.GetByName(color) 
                                                 as OkObjectResult;
           var returnColor = response.Value as Color;
           Assert.NotNull(returnColor);
           Assert.Equal(color.ToUpper(),returnColor.Name.ToUpper());
        }
    }
}

3. Docker Configuration

Now let's configure Docker. Create a file named Dockerfile at the root of the project. We will use the ASP.NET Core Runtime and the .NET SDK for .NET 5, both available on DockerHub. We will include both projects — Colors.Tests and Colors.WebApi — so they are all compiled. The file should look like this:

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
 
COPY Colors.sln ./
COPY Colors.WebApi/*.csproj ./Colors.WebApi/
COPY Colors.Tests/*.csproj ./Colors.Tests/
 
RUN dotnet restore
COPY . .
 
WORKDIR /src/Colors.WebApi
RUN dotnet build -c Release -o /app
WORKDIR /src/Colors.Tests
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
 
FROM base AS final
WORKDIR /app
 
COPY --from=publish /app .
CMD ASPNETCORE_URLS=http://*:$PORT dotnet Colors.WebApi.dll

The Dockerfile essentially describes the publication routine we would normally perform manually. It copies the entire project into the image, restores dependencies, runs a release build, and finally publishes the project — generating the correct output files and running it.

4. Configuring Github Actions

This step could also have been done first — you could have cloned the project and started development from there.

Assuming you followed the article flow, you will need to create a project on Github. Once that is done, go to your repository and open the Actions tab.

We will look for the .NET Workflow, which generates a .yml file. This is where your configuration lives — you define which steps should run during the continuous integration process. As mentioned, we will configure the test and build steps using the Dockerfile image we set up earlier. Modify the file so it looks like this:

name: .NET 
on:  
   push:    
      branches: [ master ]  
   pull_request:    
      branches: [ master ] 
jobs:  
   build:     
      runs-on: ubuntu-latest     
steps:    
   - uses: actions/checkout@v2    
   - name: Setup .NET      
     uses: actions/setup-dotnet@v1      
     with:        
       dotnet-version: 5.0.100    
   - name: Restore dependencies      
     run: dotnet restore    
   - name: Build      
     run: dotnet build --no-restore    
   - name: Test      
     run: dotnet test --no-build --verbosity normal    
   - name: Docker Build      
     run: docker build . --file Dockerfile --tag colors-api

Now that you have configured your remote Github project, if you have not connected it to your local project yet, run the following from the root of your project:

git init
git remote add origin {your repository address}
git pull

Now download the inserted configurations, add your files, and commit.

git add .
git commit -m "first commit"
git push -u origin master

5. Conclusion

After committing, you can go to your project in Github Actions and watch all the steps running. Using continuous integration in your projects greatly improves delivery quality — and implementing it in personal projects is excellent practice.