1# Dotnet {#dotnet}
2
3## Local Development Workflow {#local-development-workflow}
4
5For local development, it's recommended to use nix-shell to create a dotnet environment:
6
7```nix
8# shell.nix
9with import <nixpkgs> {};
10
11mkShell {
12 name = "dotnet-env";
13 packages = [
14 dotnet-sdk_3
15 ];
16}
17```
18
19### Using many sdks in a workflow {#using-many-sdks-in-a-workflow}
20
21It's very likely that more than one sdk will be needed on a given project. Dotnet provides several different frameworks (E.g dotnetcore, aspnetcore, etc.) as well as many versions for a given framework. Normally, dotnet is able to fetch a framework and install it relative to the executable. However, this would mean writing to the nix store in nixpkgs, which is read-only. To support the many-sdk use case, one can compose an environment using `dotnetCorePackages.combinePackages`:
22
23```nix
24with import <nixpkgs> {};
25
26mkShell {
27 name = "dotnet-env";
28 packages = [
29 (with dotnetCorePackages; combinePackages [
30 sdk_3_1
31 sdk_5_0
32 ])
33 ];
34}
35```
36
37This will produce a dotnet installation that has the dotnet 3.1, 3.0, and 2.1 sdk. The first sdk listed will have it's cli utility present in the resulting environment. Example info output:
38
39```ShellSession
40$ dotnet --info
41.NET Core SDK (reflecting any global.json):
42 Version: 3.1.101
43 Commit: b377529961
44
45...
46
47.NET Core SDKs installed:
48 2.1.803 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/sdk]
49 3.0.102 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/sdk]
50 3.1.101 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/sdk]
51
52.NET Core runtimes installed:
53 Microsoft.AspNetCore.All 2.1.15 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.AspNetCore.All]
54 Microsoft.AspNetCore.App 2.1.15 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.AspNetCore.App]
55 Microsoft.AspNetCore.App 3.0.2 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.AspNetCore.App]
56 Microsoft.AspNetCore.App 3.1.1 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.AspNetCore.App]
57 Microsoft.NETCore.App 2.1.15 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.NETCore.App]
58 Microsoft.NETCore.App 3.0.2 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.NETCore.App]
59 Microsoft.NETCore.App 3.1.1 [/nix/store/iiv98i2jdi226dgh4jzkkj2ww7f8jgpd-dotnet-core-combined/shared/Microsoft.NETCore.App]
60```
61
62## dotnet-sdk vs dotnetCorePackages.sdk {#dotnet-sdk-vs-dotnetcorepackages.sdk}
63
64The `dotnetCorePackages.sdk_X_Y` is preferred over the old dotnet-sdk as both major and minor version are very important for a dotnet environment. If a given minor version isn't present (or was changed), then this will likely break your ability to build a project.
65
66## dotnetCorePackages.sdk vs dotnetCorePackages.runtime vs dotnetCorePackages.aspnetcore {#dotnetcorepackages.sdk-vs-dotnetcorepackages.runtime-vs-dotnetcorepackages.aspnetcore}
67
68The `dotnetCorePackages.sdk` contains both a runtime and the full sdk of a given version. The `runtime` and `aspnetcore` packages are meant to serve as minimal runtimes to deploy alongside already built applications.
69
70## Packaging a Dotnet Application {#packaging-a-dotnet-application}
71
72To package Dotnet applications, you can use `buildDotnetModule`. This has similar arguments to `stdenv.mkDerivation`, with the following additions:
73
74* `projectFile` has to be used for specifying the dotnet project file relative to the source root. These usually have `.sln` or `.csproj` file extensions. This can be an array of multiple projects as well.
75* `nugetDeps` has to be used to specify the NuGet dependency file. Unfortunately, these cannot be deterministically fetched without a lockfile. This file should be generated using `nuget-to-nix` tool, which is available in nixpkgs.
76* `executables` is used to specify which executables get wrapped to `$out/bin`, relative to `$out/lib/$pname`. If this is unset, all executables generated will get installed. If you do not want to install any, set this to `[]`.
77* `runtimeDeps` is used to wrap libraries into `LD_LIBRARY_PATH`. This is how dotnet usually handles runtime dependencies.
78* `buildType` is used to change the type of build. Possible values are `Release`, `Debug`, etc. By default, this is set to `Release`.
79* `dotnet-sdk` is useful in cases where you need to change what dotnet SDK is being used.
80* `dotnet-runtime` is useful in cases where you need to change what dotnet runtime is being used. This can be either a regular dotnet runtime, or an aspnetcore.
81* `dotnet-test-sdk` is useful in cases where unit tests expect a different dotnet SDK. By default, this is set to the `dotnet-sdk` attribute.
82* `testProjectFile` is useful in cases where the regular project file does not contain the unit tests. By default, this is set to the `projectFile` attribute.
83* `disabledTests` is used to disable running specific unit tests. This gets passed as: `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all unit test frameworks.
84* `dotnetRestoreFlags` can be used to pass flags to `dotnet restore`.
85* `dotnetBuildFlags` can be used to pass flags to `dotnet build`.
86* `dotnetTestFlags` can be used to pass flags to `dotnet test`.
87* `dotnetInstallFlags` can be used to pass flags to `dotnet install`.
88* `dotnetFlags` can be used to pass flags to all of the above phases.
89
90Here is an example `default.nix`, using some of the previously discussed arguments:
91```nix
92{ lib, buildDotnetModule, dotnetCorePackages, ffmpeg }:
93
94buildDotnetModule rec {
95 pname = "someDotnetApplication";
96 version = "0.1";
97
98 src = ./.;
99
100 projectFile = "src/project.sln";
101 nugetDeps = ./deps.nix; # File generated with `nuget-to-nix path/to/src > deps.nix`.
102
103 dotnet-sdk = dotnetCorePackages.sdk_3_1;
104 dotnet-runtime = dotnetCorePackages.net_5_0;
105 dotnetFlags = [ "--runtime linux-x64" ];
106
107 executables = [ "foo" ]; # This wraps "$out/lib/$pname/foo" to `$out/bin/foo`.
108 executables = []; # Don't install any executables.
109
110 runtimeDeps = [ ffmpeg ]; # This will wrap ffmpeg's library path into `LD_LIBRARY_PATH`.
111}
112```