A quick guide on how to set up csharp projects with various features
-
-
Save Gameghostify/045382dd75a0888afd213fd89a34d1a6 to your computer and use it in GitHub Desktop.
using dotnet cli
- create source directory (
./src
) that will hold the source code - run
dotnet new [options]
(e.g.dotnet new --output ./src/<project name> web
) to generate a new project - remove unneeded generated files
To use a single dockerfile, but still get dotnet watch
auto-reloading to work,
use incremental builds.
Here, a dockerfile with two build steps is set up:
###############################################################################
# development build step
#
# here, the dotnet sdk (version 3.1, update if necessary) is used so any needed
# `dotnet` commands (e.g. `dotnet restore`) can be used during the build
###############################################################################
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app/
# restore dependencies before building
# separate step so docker can cache the dependencies
COPY ./MyProject.Api.csproj ./
RUN dotnet restore
# build in docker container
# still included in build-env step since we need the sdk to run dotnet-publish
COPY ./ ./
RUN dotnet publish -c Release -o ./out/
###############################################################################
# production build step
#
# here the previously build app is copied from the previous step
# (see `--from=build-env`)
###############################################################################
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime-env
WORKDIR /app/
COPY --from=build-env /app/out ./
ENTRYPOINT [ "dotnet", "MyProject.Api.dll" ]
If you want your application to be automatically reloaded every time it's changed, your app needs to
be started with dotnet watch run
.
In your docker-compose.yml
:
- only build until reaching the required step (development/
build-env
) - mount your source as volume
and run
dotnet watch run
once the build step is completed:
services:
# ...
api:
build:
context: ./src/MyProject.Api # directory that contains the Dockerfile
target: build-env
volumes:
- ./src/MyProject.Api
command: dotnet watch run
# ...
using target
requires docker-compose file version 3.4 or greater
In the end, all that really matters is that your app is started using dotnet watch run
.
How you do this is entirely up to you. The solution above is production ready though.
There's one more thing, however:
based on a great article by Nate McMaster: https://natemcmaster.com/blog/2017/11/13/dotnet-watch-and-docker/
One of the most common problems with making Docker and Visual Studio (Code) work well is that the files in the obj/ and bin/ folders need to be different inside and outside the Docker container. If they overlap, you’ll get errors, including “Version for package ‘Microsoft.DotNet.Watcher.Tools’ could not be resolve”, issues with the runtime store, and more.
To resolve this, we will move the location of the obj/ and bin/ folders to sit next to the project directory, not inside it.
Add a file named Directory.Build.props to your project with these contents:
<Project> <PropertyGroup> <BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/../obj/</BaseIntermediateOutputPath> <BaseOutputPath>$(MSBuildProjectDirectory)/../bin/</BaseOutputPath> </PropertyGroup> </Project>
(emphasis mine)
asp.net core won't receive connections by default in docker-compose, since it's listening to port 5000
to change that, do the following:
- Add an env var called
ASPNETCORE_URLS
and set it tohttp://+:80
- Map the wanted port of the application (e.g.
5000
if you want to be able to connect to your app usinghttp://localhost:5000
) to 80. (e.g.docker run -p 5000:80 ...
)
based on a great article by Aaron Powell: https://www.aaron-powell.com/posts/2019-04-04-debugging-dotnet-in-docker-with-vscode/
vsdbg is a debugger for vscode/vs ide with it, you can debug running .NET Core applications on remote hosts (e.g. docker containers), as long as it's installed on that host
to download and unzip it, run this bash
command:
curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -l <directory>
(the debugger will be downloaded and extracted to the <directory>
specified above)
- extract vsdbg into it's own directory (e.g.
./vsdbg
) - if using git/other VCS, add that directory to your
.gitignore
/your-VCS's-ignore-file file - add the directory (here
./vsdbg
) as a volume (in thedocker-compose.yml
file):
# ...
services:
api:
# build:
# context: ./src/MyProject.Api/
# dockerfile: dev.Dockerfile
# depends_on:
# - migrated_database
volumes:
# - ./src/Rollingbets.Api:/usr/src/api
# =====================================================================
- ./vsdbg:/vsdbg
# =====================================================================
# ports:
# - 5000:80
# environment:
# - ASPNETCORE_URLS=http://+:80
# env_file:
# - .env
# - db.env
# ...
then create the vscode launch configuration:
a great tool for database migrations is flyway
to set up flyway migrations for docker-compose, do the following:
- create a new directory for the migration files (e.g.
migration/
) - create a new file called, for example,
flyway.env
(db.env
would be a good alternative) - set up your
flyway.env
anddocker-compose.yml
as below
FLYWAY_USER=<db username>
FLYWAY_PASSWORD=<db password>
# jdbc:<db name>://<docker-compose service name>:<db port>/<target database>
# for example:
FLYWAY_URL=jdbc:postgresql://database:5432/myCoolDatabase
FLYWAY_DRIVER=org.postgresql.Driver
version: "3"
services:
database:
image: postgres:12
volumes:
- db-data:/var/lib/postgresql/data
env_file:
# contains database info such as database name, user, and password
# ! this should likely match up with the information in flyway.env
- postgres.env
ports:
- 5432:5432
migrated_database:
image: flyway/flyway
depends_on:
- database
env_file:
- flyway.env
volumes:
- ./<name of your local migration folder>:/flyway/sql # e.g. "./migration:/flyway/sql"
command: migrate -connectRetries=60 # tries to connect 60 times before aborting (needed since postgresql won't start up immediately)
# another alternative would be `wait-for-it.sh` (https://github.com/vishnubob/wait-for-it)
api:
depends_on:
# services can now depend upon the migrated database
- migrated_database
# ...
#...