-
Add a reference to the NuGet package
Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
.This can be done from the command line using
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
-
Add a DbContext health check in
Program.cs
by adding the following code to to the list of services, after the database is configured:builder.Services.AddHealthChecks() .AddDbContextCheck<ApplicationDbContext>();
-
Wire up health checks by modifying the
UseEndpoints
to add a call toendpoints.MapHealthChecks("/health");
. This will configure the health checks on the/health
end point. -
Test the end point by navigating to
/health
, it should return the textHealthy
.
-
Add a reference to the NuGet package
Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
.This can be done from the command line using
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
-
Add a DbContext health check in
Program.cs
by adding the following code to to the list of services, after the database is configured:builder.Services.AddHealthChecks() .AddDbContextCheck<IdentityDbContext>();
-
Wire up health checks by modifying the
UseEndpoints
to add a call toendpoints.MapHealthChecks("/health");
. This will configure the health checks on the/health
end point. -
Test the end point by navigating to
/health
, it should return the textHealthy
.
-
Add a
CheckHealthAsync
method toIApiClient
.public interface IApiClient { ... Task<bool> CheckHealthAsync(); }
-
Implement the
CheckHealthAsync
method inApiClient
by adding the following code:public async Task<bool> CheckHealthAsync() { try { var response = await _httpClient.GetStringAsync("/health"); return string.Equals(response, "Healthy", StringComparison.OrdinalIgnoreCase); } catch { return false; } }
-
Create a
HealthChecks
folder under the root folder in the FrontEnd project. -
Create a file called
BackendHealthCheck.cs
with the following implementation:using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using FrontEnd.Services; using Microsoft.Extensions.Diagnostics.HealthChecks; namespace FrontEnd.HealthChecks { public class BackendHealthCheck : IHealthCheck { private readonly IApiClient _client; public BackendHealthCheck(IApiClient client) { _client = client; } public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken)) { if (await _client.CheckHealthAsync()) { return HealthCheckResult.Healthy(); } return HealthCheckResult.Unhealthy(); } } }
-
Register the
BackendHealthCheck
inConfigureServices
:services.AddHealthChecks() .AddCheck<BackendHealthCheck>("backend") .AddDbContextCheck<IdentityDbContext>();
-
Test the end point by navigating to
/health
, it should return the textHealthy
.
https://docs.microsoft.com/en-us/aspnet/core/publishing/#publish-to-a-folder
-
Right Click Backend | Publish
-
Select App Service, make sure the publish drop down is set to "Create Profile", click "Create Profile"
-
Fill in Name, Resource Group, Hosting Plan
-
Click "Create SQL Database", fill in name, press "New..." to create Database server, fill in fields click "OK"
-
Click "Create"
-
On the publish page click "Edit". Click Settings. Open Databases and check the box for the default database. Click Migrations and check the box to apply migrations on publish. Click Save.
-
Click the "Publish" button. When the app launches, find the Sessions section, scroll to /api/sessions/upload. Click the post button to upload your session data
-
In the FrontEnd application, open the AppSettings.json and replace the ServiceUrl with the URL from your backend in App Service.
-
Right Click Frontend | Publish
-
Select App Service, make sure the publish drop down is set to "Create Profile", click "Create Profile"
-
Fill in name, same resource group as above and same hosting plan as above.
-
Click "Create Database", fill in name, select the same database server from above, fill in the same password as above and change the Connection string name to "IdentityDbContextConnection". Press OK.
-
Click "Create".
-
On the publish page click "Edit". Click Settings. Open Databases and check the box for the default database. Click Migrations and check the box to apply migrations on publish. Click Save.
-
Click the "Publish" button.
Prerequisites
Enable Database Errors and switch to SQL since that is what runs in the container
For both the front end and backend make the following code chanages:
-
Add the package "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore"
-
Add the database error page in Startup.cs, after app.UseDeveloperExceptionPage() add app.UseDatabaseErrorPage():
app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage();
-
In the backend project, in Startup.cs, comment out the code to support SQLite:
//if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) //{ options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")); //} //else //{ // options.UseSqlite("Data Source=conferences.db"); //}
Add Docker support to the BackEnd project by right clicking the project file and selecting Add > Docker Support
A Dockerfile is added to the BackEnd project.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["BackEnd/BackEnd.csproj", "BackEnd/"]
COPY ["ConferenceDTO/ConferenceDTO.csproj", "ConferenceDTO/"]
RUN dotnet restore "BackEnd/BackEnd.csproj"
COPY . .
WORKDIR "/src/BackEnd"
RUN dotnet build "BackEnd.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "BackEnd.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "BackEnd.dll"]
Add Container Orchestration support to the project, right click the project file and selecting Add > Container Orchestration Support Select Docker Comppose and click OK. This creates a docker-compose project with a docker.compose.yml file.
Repeat the same step for the FrontEnd project. The Dockerfile is added to the project for it.
Add Docker support to the FrontEnd project by right clicking the project file and selecting Add > Docker Support
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["FrontEnd/FrontEnd.csproj", "FrontEnd/"]
COPY ["ConferenceDTO/ConferenceDTO.csproj", "ConferenceDTO/"]
RUN dotnet restore "FrontEnd/FrontEnd.csproj"
COPY . .
WORKDIR "/src/FrontEnd"
RUN dotnet build "FrontEnd.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "FrontEnd.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "FrontEnd.dll"]
Add Container Orchestration support to the project, right click the project file and selecting Add > Container Orchestration Support Select Docker Comppose and click OK.
The docker-compose.yml file is updated to reflect that there are two projects to build images.
version: '3.4'
services:
frontend:
image: ${DOCKER_REGISTRY-}frontend
build:
context: .
dockerfile: FrontEnd/Dockerfile
backend:
image: ${DOCKER_REGISTRY-}backend
build:
context: .
dockerfile: BackEnd/Dockerfile
In the previous architecture, there were some setting and manual orchestration to start up and wire the applications together.
- BackEnd tested for OS type and set the application to use SQL Server or SQLite
- FrontEnd application had the API url set in the appsetting.json file.
Using Docker, adding a container for SQL Server and linking the containers in the compose file simplifies this.
Open the docker-compose.yml file and add the following entry. Note the $ is doubled for escaping
db:
image: "microsoft/mssql-server-linux"
environment:
SA_PASSWORD: "ConferencePlanner1234$$"
ACCEPT_EULA: "Y"
Since the BackEnd application must have connectivity and cannot start until the database container is ready. Add the depends_on entry to the backend definition in the compose file.
backend:
image: backend
build:
context: .
dockerfile: BackEnd/Dockerfile
depends_on:
- db
Finally, change the connection string for the database in the BackEnd\appsettings.json file.
"ConnectionStrings": {
"DefaultConnection": "Server=db;Initial Catalog=ConferencePlanner;User=sa;Password=ConferencePlanner1234$;MultipleActiveResultSets=true"
}
In the docker-compose.yml file, add the links section to the frontend definition. This sets up the host name in the Docker networking allowing for the web application to call the API by name. http://backend
frontend:
image: frontend
build:
context: .
dockerfile: FrontEnd/Dockerfile
links:
- backend
Change the value for the ServiceUrl in FrontEnd/appsetting.json
{
"ServiceUrl": "http://backend/",
Remove or comment out the app.UseHttpsRedirection();
in BackEnd\Startuo.cs.
Once the changes are complete, F5 to build start the application in Docker. Debugging is still available in all projects, but now the application is running in containers.
Changes can be made to Razor pages and seen immediately without rebuilds, however and *.cs file changes require rebuilds.
Create and add the following Dockerfile for the BackEnd application.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["BackEnd/BackEnd.csproj", "BackEnd/"]
COPY ["ConferenceDTO/ConferenceDTO.csproj", "ConferenceDTO/"]
RUN dotnet restore "BackEnd/BackEnd.csproj"
COPY . .
WORKDIR "/src/BackEnd"
RUN dotnet build "BackEnd.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "BackEnd.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
Create and add the following Dockerfile for the FrontEnd application.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["BackEnd/BackEnd.csproj", "BackEnd/"]
COPY ["ConferenceDTO/ConferenceDTO.csproj", "ConferenceDTO/"]
RUN dotnet restore "BackEnd/BackEnd.csproj"
COPY . .
WORKDIR "/src/BackEnd"
RUN dotnet build "BackEnd.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "BackEnd.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
At the root of the ConferencePlanner solution, add the following docker-compose.yml file.
version: '3.4'
services:
frontend:
image: ${DOCKER_REGISTRY-}frontend
build:
context: .
dockerfile: FrontEnd/Dockerfile
backend:
image: ${DOCKER_REGISTRY-}backend
build:
context: .
dockerfile: BackEnd/Dockerfile
depends_on:
- db
db:
image: "microsoft/mssql-server-linux"
environment:
SA_PASSWORD: "ConferencePlanner1234$$"
ACCEPT_EULA: "Y"
At the root of the ConferencePlanner solution, add the following docker-compose.override.yml file.
version: '3.4'
services:
backend:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_HTTPS_PORT=44370
ports:
- "63145:80"
- "44370:443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
frontend:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_HTTPS_PORT=44384
ports:
- "56004:80"
- "44384:443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
Change the connection string for the database in the BackEnd\appsettings.json file.
"ConnectionStrings": {
"DefaultConnection": "Server=db;Initial Catalog=ConferencePlanner;User=sa;Password=ConferencePlanner1234$;MultipleActiveResultSets=true"
}
Change the value for the ServiceUrl in FrontEnd/appsetting.json
{
"ServiceUrl": "http://backend/",
Remove or comment out the app.UseHttpsRedirection();
in BackEnd\Startuo.cs.
- Build the Docker images
docker-compose build
- Run
docker-compose up -d
to start the application - Run
docker-compose down
to stop the application - Open the application at http://localhost:5002
Next: Session #7 - Challenges | Previous: Session #5 - Add Agenda