Summary: end to end application- design with web api connecting to DB and building all services with docker compose and complete details related to configuring certificates and other fundamentals and coding standards
Advantages of Docker
Docker simplifies application development by allowing developers to package their applications into portable, lightweight containers. These containers ensure that the application can run consistently across different systems without worrying about underlying infrastructure.
Here are some key advantages:
- Portability: Docker containers include everything needed to run an application, making them portable across systems that support Docker.
- Consistency: Containers ensure that applications behave the same way across development, testing, and production environments, eliminating the “works on my machine” problem.
- Isolation: Each container runs independently, so issues in one container won’t affect others, making maintenance and scaling easier.
- Scalability: Docker allows for quick scaling of services to handle increased traffic by spawning additional containers.
Why Use Docker Compose for Multiple Services?
Docker Compose is a tool designed for managing multi-container Docker applications, making it ideal for projects that require multiple services, like a Web API, SQL Server, and Redis.
Advantages of Docker Compose include:
- Simplified Setup: With Docker Compose, you define and run multiple services from a single configuration file.
- Service Orchestration: Compose ensures services are started in the correct order based on dependencies (e.g., ensuring a database is up before the Web API).
In my project, FashionClothesAndTrends. Docker Compose is used to manage the ASP.NET WebAPI, SQL Server, and Redis services. The setup simplifies running the entire system with a single command, ensuring that all components work seamlessly together.
Detailed Breakdown of Web API Components
Let’s dive deeper into the components of the Web API project. We’ll focus on key elements including the ApplicationDbContext class, caching in the ClothingController, configuration in ApplicationServicesExtensions, and how they are wired together in the Program.cs.
1. ApplicationDbContext Class
The ApplicationDbContext class is the database context for the Web API. It inherits from IdentityDbContext, which is part of the ASP.NET Core Identity framework. This class is responsible for managing the interaction between the Web API and the database.
Here’s a breakdown of the ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext<User, AppRole, string,
IdentityUserClaim<string>, AppUserRole, IdentityUserLogin<string>,
IdentityRoleClaim<string>, IdentityUserToken<string>>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) {}
public DbSet<ClothingItem> ClothingItems { get; set; }
// ... and other entities
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Apply configurations using Fluent API
modelBuilder.ApplyConfiguration(new UserConfiguration());
modelBuilder.ApplyConfiguration(new ClothingItemConfiguration());
// ... and other entity configurations
// Seed initial data
SeedDataInitializer.ContextSeed(modelBuilder);
}
}
Key Points:
- Inherits from IdentityDbContext: This gives the class built-in functionality for handling user authentication, roles, claims, and tokens.
- DbSets: These properties represent the tables in the database (ClothingItems, etc.).
- Fluent API Configuration: Uses ApplyConfiguration to apply additional configuration for each entity (UserConfiguration, etc.).
- Seeding Data: Initial data can be seeded using the SeedDataInitializer.
2. GetClothingItems Method in ClothingController with Caching
In the ClothingController class, we have a method called GetClothingItems. This method is used to retrieve a list of clothing items, and it is cached using a custom [Cached] attribute.
[Cached(60)]
[HttpGet]
public async Task<ActionResult<Pagination<ClothingItemDto>>> GetClothingItems(
[FromQuery] ClothingSpecParams clothingSpecParams)
{
try
{
return Ok(await _clothingItemService.GetClothingItems(clothingSpecParams));
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
Key Points:
- Cached(60): This custom attribute applies caching to the response of this endpoint. The value 60 represents the cache duration in seconds. This means the response from this method will be stored in the cache for 60 seconds, reducing load on the database for repeated requests within that time frame.
- Dependency Injection: The method depends on _clothingItemService, which is injected via the constructor. This service contains the business logic for retrieving clothing items.
3. Application Services Configuration in ApplicationServicesExtensions
The ApplicationServicesExtensions class provides a centralized place to configure services for dependency injection. These services include database connection settings, Redis configuration and other essential services required by the application.
public static class ApplicationServicesExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services,
IConfiguration config)
{
// Configuring SQL Server connection
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(config.GetConnectionString("DefaultDockerDbConnection"));
});
// Configuring Redis connection
services.AddSingleton<IConnectionMultiplexer>(c =>
{
var options = ConfigurationOptions.Parse(config.GetConnectionString("Redis"), true);
return ConnectionMultiplexer.Connect(options);
});
// Additional service registrations
return services;
}
}
Key Points:
- AddDbContext: This method sets up the ApplicationDbContext with a connection to SQL Server using the connection string defined in appsettings.json. In this case, it’s set to use the Docker SQL Server instance.
- AddSingleton: This registers Redis as a singleton, meaning there will be a single instance of the Redis connection multiplexer shared across the application.
4. Application of AddApplicationServices in Program.cs
In the Program.cs, this extension method is called to register the services at runtime:
builder.Services.AddApplicationServices(builder.Configuration);
Key Points:
- builder.Services: This represents the service collection used to register all services for dependency injection.
- builder.Configuration: This provides access to the application’s configuration (e.g., appsettings.json). The connection strings and Redis settings are read from here.
5. Configuration in appsettings.json
The appsettings.json file contains the configuration settings for the application, including connection strings for the database and Redis.
{
"ConnectionStrings": {
"DefaultDockerDbConnection": "Server=sql_server2022,1433;Database=FashionClothesAndTrendsDB;User Id=sa;Password=MyPass@word90_;MultipleActiveResultSets=true;TrustServerCertificate=True",
"Redis": "redis:6379,abortConnect=false",
}
}
Docker Configuration for ASP.NET Core Application
In this section, we will explore the Dockerfile used in the FashionClothesAndTrends.WebAPI, discuss running ASP.NET Core with HTTPS inside Docker, explain how to create a development certificate, and take a detailed look at the docker-compose.debug.yml file.
1. Dockerfile Breakdown
The Dockerfile located at FashionClothesAndTrends.WebAPI/Dockerfile is used to containerize the ASP.NET Core application. Here’s the breakdown of its stages:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["FashionClothesAndTrends.WebAPI/FashionClothesAndTrends.WebAPI.csproj", "FashionClothesAndTrends.WebAPI/"]
COPY ["FashionClothesAndTrends.Application/FashionClothesAndTrends.Application.csproj", "FashionClothesAndTrends.Application/"]
COPY ["FashionClothesAndTrends.Domain/FashionClothesAndTrends.Domain.csproj", "FashionClothesAndTrends.Domain/"]
COPY ["FashionClothesAndTrends.Infrastructure/FashionClothesAndTrends.Infrastructure.csproj", "FashionClothesAndTrends.Infrastructure/"]
RUN dotnet restore "FashionClothesAndTrends.WebAPI/FashionClothesAndTrends.WebAPI.csproj"
COPY . .
WORKDIR "/src/FashionClothesAndTrends.WebAPI"
RUN dotnet build "FashionClothesAndTrends.WebAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "FashionClothesAndTrends.WebAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
RUN dotnet tool install --global dotnet-ef
ENV PATH="${PATH}:/root/.dotnet/tools"
ENTRYPOINT ["dotnet", "FashionClothesAndTrends.WebAPI.dll"]
Main Key Points:
- EXPOSE 80 and EXPOSE 443: Exposes ports 80 (HTTP) and 443 (HTTPS), allowing the container to serve web traffic.
- WORKDIR /src: Sets the working directory inside the container where the source code will be placed.
- COPY: Copies the .csproj files for the WebAPI, Application, Domain, and Infrastructure layers into the container for the build process.
- WORKDIR “/src/FashionClothesAndTrends.WebAPI”: Sets the working directory to the WebAPI project folder.
- RUN dotnet tool install — global dotnet-ef: Installs the Entity Framework Core (EF) command-line tool.
- ENV PATH=”${PATH}:/root/.dotnet/tools”: Updates the environment PATH to include the EF tools for use during runtime.
- ENTRYPOINT: Defines the command that will be executed when the container starts (dotnet FashionClothesAndTrends.WebAPI.dll).
2. Running ASP.NET Core with HTTPS inside Docker
When running ASP.NET Core inside Docker with HTTPS, it is essential to bind a certificate to the container. This ensures secure connections to the API. Below are the steps to create and use a development certificate for localhost.
Create a Dev Certificate for Localhost On Windows, you can generate and trust a local HTTPS development certificate using the following commands:
dotnet dev-certs https -ep $env:USERPROFILE/.aspnet/https/aspnetapp.pfx -p MyPass@word90_
dotnet dev-certs https --trust
In my project, I’ve executed the dotnet dev-certs https commands at the FashionClothesAndTrends level instead of within the FashionClothesAndTrends.WebAPI directory.
- dotnet dev-certs https -ep: Exports a self-signed HTTPS certificate to a .pfx file.
- MyPass@word90_: An example of password to protect the certificate.
- dotnet dev-certs https — trust: Trusts the certificate on your local machine, allowing it to be used with HTTPS.
The appsettings.json should contain the following Kestrel configuration for HTTPS:
{
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://+:443",
"Certificate": {
"Path": "/https/aspnetapp.pfx",
"Password": "MyPass@word90_"
}
}
}
}
}
This configuration specifies that Kestrel should use HTTPS and binds it to port 443. The certificate is loaded from the /https/aspnetapp.pfx file, with the password provided in the docker-compose.debug.yml file.
3. Docker Compose File
The docker-compose.debug.yml file orchestrates the different services used by the application (e.g., the Web API, SQL Server, Redis) into a cohesive environment.
version: "3.9"
services:
webapi:
build:
context: .
dockerfile: ./FashionClothesAndTrends.WebAPI/Dockerfile
restart: always
ports:
- "5000:80"
- "5001:443"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=5001
- ASPNETCORE_Kestrel__Certificates__Default__Password=MyPass@word90_
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
- ConnectionStrings__DefaultDockerDbConnection=Server=sql_server2022,1433;Database=FashionClothesAndTrendsDB;User Id=sa;Password=MyPass@word90_;MultipleActiveResultSets=true;TrustServerCertificate=True
- Redis__ConnectionString=redis:6379
links:
- sql
- redis
depends_on:
- sql
- redis
networks:
- app_network
volumes:
- ~/.aspnet/https:/https:ro
redis:
image: redis:latest
ports:
- "6379:6379"
command: ["redis-server", "--appendonly", "yes", "--timeout", "0"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app_network
sql:
image: mcr.microsoft.com/mssql/server:2022-latest
container_name: sql_server2022
environment:
SA_PASSWORD: "MyPass@word90_"
ACCEPT_EULA: "Y"
ports:
- "1433:1433"
healthcheck:
test: CMD /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P MyPass@word90_ -Q "SELECT 1" || exit 1
timeout: 20s
retries: 10
start_period: 10s
networks:
- app_network
networks:
app_network:
driver: bridge
Main Key Points:
- build: Defines how to build the WebAPI service using the Dockerfile.
- ports: Maps ports 5000 (HTTP) and 5001 (HTTPS) on the host to ports 80 and 443 in the container.
- environment: Sets environment variables for ASP.NET Core, including HTTPS configuration (ASPNETCORE_HTTPS_PORT, ASPNETCORE_Kestrel__Certificates).
- links: Connects the webapi service to the sql and redis services.
- depends_on: Ensures the sql and redis services are up and running before starting the webapi service.
- volumes: Mounts the HTTPS certificate from the host into the container as read-only.
- Redis: Uses the official Redis image and is exposed on port 6379. It is configured to run indefinitely (timeout=0).
- SQL Server: Uses the official SQL Server 2022 image, with a health check to ensure the database is running before the WebAPI service starts.
When the Docker Compose Command Runs
In this section, we will focus on launching the project using the Docker Compose command. The full command you’ll be using is:
docker-compose -f docker-compose.debug.yml up --build
When you run the command docker-compose -f docker-compose.debug.yml up — build, Docker will:
- Check for the necessary images (SQL Server and Redis).
- If they aren’t present locally, Docker will download them automatically. Build your WebAPI service as per the Dockerfile in the FashionClothesAndTrends.WebAPI directory.
- Run the containers: SQL Server, Redis, and your WebAPI will start up in their own isolated containers, and the services will be linked together as defined in the docker-compose.debug.yml file.
By automating this process with Docker Compose, it simplifies the experience for the user, ensuring that everything is pulled and configured without needing to run multiple docker pull commands manually.
Conclusion
Docker greatly simplifies the development and deployment of modern applications by containerizing the necessary services into easily manageable components. With Docker Compose, you can orchestrate multiple services like a WebAPI, SQL Server, and Redis, all from a single configuration file.
In this guide, we demonstrated how to:
- Leverage Docker to run ASP.NET Core applications, MS SQL Server, and Redis within containers, ensuring consistency across different environments.
- Use Docker Compose to manage multiple services seamlessly, allowing for the automatic pulling of necessary images like SQL Server and Redis and creating a cohesive network of services.
- Run ASP.NET Core with HTTPS within Docker, ensuring secure connections through a trusted local development certificate.
- By utilizing these Docker and Docker Compose capabilities, you can streamline your workflow, automate the configuration of complex environments, and minimize the risk of “it works on my machine” issues.
No comments:
Post a Comment