DotNET: Difference between revisions
Lord-Valen (talk | contribs) m Use the correct command name. |
group into sections, add intro text from wikipedia |
||
| Line 1: | Line 1: | ||
From [https://en.wikipedia.org/wiki/.NET Wikipedia] | |||
<blockquote> | |||
The .NET platform (formerly named .NET Core) is a free and open-source, managed computer software framework for Windows, Linux, and macOS operating systems. It is a cross-platform successor to the .NET Framework. The project is mainly developed by Microsoft employees by way of the .NET Foundation and is today released under an MIT License. | |||
</blockquote> | |||
== NativeAOT == | |||
This is relevant for NixOS only. | |||
[https://github.com/Mic92/nix-ld nix-ld] is needed: | |||
<syntaxHighlight lang=nix> | |||
{ | |||
programs.nix-ld.enable = true; | |||
} | |||
</syntaxHighlight> | |||
Now we will need a bunch of native dependencies. Here's an example of a shell: | |||
<syntaxHighlight lang=nix> | |||
with import <nixpkgs> {}; | |||
pkgs.mkShell rec { | |||
dotnetPkg = | |||
(with dotnetCorePackages; combinePackages [ | |||
sdk_7_0 | |||
]); | |||
deps = [ | |||
zlib | |||
zlib.dev | |||
openssl | |||
dotnetPkg | |||
]; | |||
NIX_LD_LIBRARY_PATH = lib.makeLibraryPath ([ | |||
stdenv.cc.cc | |||
] ++ deps); | |||
NIX_LD = "${pkgs.stdenv.cc.libc_bin}/bin/ld.so"; | |||
nativeBuildInputs = [ | |||
] ++ deps; | |||
shellHook = '' | |||
DOTNET_ROOT="${dotnetPkg}"; | |||
''; | |||
} | |||
</syntaxHighlight> | |||
== Global Tools == | |||
Local installation of .NET global tools is fully supported and preferred when possible - more info [https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools#install-a-local-tool in the Microsoft docs]. | |||
For globally installing .NET tools, search if they are available as Nix packages - they are packaged as any other normal | |||
.NET binary, using <code>buildDotnetModule</code>. For .NET tools with no source available, or those hard to build from source, <code>buildDotnetGlobalTool</code> is available. See [https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/dotnet.section.md#dotnet-global-tools-dotnet-global-tools dotnet nixpkgs manual] for more info. | |||
Note that Nix-packaged .NET tools use a special wrapper (toggled by <code>useDotnetFromEnv</code> option in <code>buildDotnetModule</code>) that automatically picks up .NET install from the user environment. If you want to use a | |||
different SDK version with a Nix-packaged .NET tools than the default, make sure the <code>dotnet</code> CLI of your wanted SDK version is installed and available. | |||
== Packaging == | |||
.NET packages can be built with <code>buildDotnetModule</code> | .NET packages can be built with <code>buildDotnetModule</code> | ||
| Line 33: | Line 93: | ||
Remember to build and run the <code>fetch-deps</code> script after NuGet packages are updated, or building the derivation will fail. | Remember to build and run the <code>fetch-deps</code> script after NuGet packages are updated, or building the derivation will fail. | ||
== Building non-.NET Core packages == | === Building non-.NET Core packages === | ||
Keep in mind that building projects which don't use the .NET SDK (formerly the .NET Core SDK) and its <code>dotnet</code> CLI tool isn't supported. | Keep in mind that building projects which don't use the .NET SDK (formerly the .NET Core SDK) and its <code>dotnet</code> CLI tool isn't supported. | ||
| Line 41: | Line 101: | ||
Just remember to add `mono` to `buildInputs` and generate a wrapper script in `postInstall`. | Just remember to add `mono` to `buildInputs` and generate a wrapper script in `postInstall`. | ||
== Packaging ASP.NET projects == | === Packaging ASP.NET projects === | ||
Currently building ASP.NET project as Nix package produces a website that does not work correctly out of the box because the executable can not find <code>wwwroot</code>, so all the static assets won't load with 404. | Currently building ASP.NET project as Nix package produces a website that does not work correctly out of the box because the executable can not find <code>wwwroot</code>, so all the static assets won't load with 404. | ||
| Line 106: | Line 166: | ||
See also: setting up SSL certificates using [[ACME]] | See also: setting up SSL certificates using [[ACME]] | ||
== .NET location: Not found == | |||
== Examples == | |||
=== Running Rider with dotnet & PowerShell === | |||
Rider has better compatibility when run in FHS mode | |||
Rider package<syntaxhighlight lang="nix"> | |||
pkgs.jetbrains.rider | |||
</syntaxhighlight>rider-fhs.nix<syntaxhighlight lang="nix"> | |||
{ pkgs ? import <nixpkgs> {} }: | |||
(pkgs.buildFHSEnv { | |||
name = "rider-env"; | |||
targetPkgs = pkgs: (with pkgs; [ | |||
dotnetCorePackages.dotnet_8.sdk | |||
dotnetCorePackages.dotnet_8.aspnetcore | |||
powershell | |||
]); | |||
multiPkgs = pkgs: (with pkgs; [ | |||
]); | |||
runScript = "nohup rider &"; | |||
}).env | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="nix"> | |||
nix-shell ./rider-fhs.nix | |||
</syntaxhighlight> | |||
This can be added as an alias to your shell if you update the reference to an absolute address, such as location within your home directory. | |||
<syntaxhighlight> | |||
run-rider = "nix-shell ~/nix/rider-fhs.nix"; | |||
</syntaxhighlight> | |||
=== Multi-SDK installation with local workload installation enabled === | |||
By default, workload installation will fail on NixOS, as dotnet will attempt to save it to $DOTNET_ROOT, which is inside the read-only Nix store. | |||
Please visit the [https://discourse.nixos.org/t/dotnet-maui-workload/20370/10 forum] for an example of a multi-SDK installation with workload changed to install to home directory. | |||
== Troubleshooting == | |||
=== .NET location: Not found === | |||
If running a .NET-build executable you get the above error, make sure the DOTNET_ROOT environment variable is set: | If running a .NET-build executable you get the above error, make sure the DOTNET_ROOT environment variable is set: | ||
| Line 117: | Line 221: | ||
See : https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables#net-sdk-and-cli-environment-variables | See : https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables#net-sdk-and-cli-environment-variables | ||
== TargetFramework value was not recognized == | === TargetFramework value was not recognized === | ||
<blockquote> | <blockquote> | ||
| Line 127: | Line 231: | ||
Wontfix: The project will build only on Windows. | Wontfix: The project will build only on Windows. | ||
== Unable to find package == | === Unable to find package === | ||
<blockquote> | <blockquote> | ||
| Line 148: | Line 252: | ||
If this still does not work, it might indicate a good time to update target frameworks and dependencies. | If this still does not work, it might indicate a good time to update target frameworks and dependencies. | ||
== See also == | == See also == | ||
Latest revision as of 22:58, 25 March 2026
From Wikipedia
The .NET platform (formerly named .NET Core) is a free and open-source, managed computer software framework for Windows, Linux, and macOS operating systems. It is a cross-platform successor to the .NET Framework. The project is mainly developed by Microsoft employees by way of the .NET Foundation and is today released under an MIT License.
NativeAOT
This is relevant for NixOS only.
nix-ld is needed:
{
programs.nix-ld.enable = true;
}
Now we will need a bunch of native dependencies. Here's an example of a shell:
with import <nixpkgs> {};
pkgs.mkShell rec {
dotnetPkg =
(with dotnetCorePackages; combinePackages [
sdk_7_0
]);
deps = [
zlib
zlib.dev
openssl
dotnetPkg
];
NIX_LD_LIBRARY_PATH = lib.makeLibraryPath ([
stdenv.cc.cc
] ++ deps);
NIX_LD = "${pkgs.stdenv.cc.libc_bin}/bin/ld.so";
nativeBuildInputs = [
] ++ deps;
shellHook = ''
DOTNET_ROOT="${dotnetPkg}";
'';
}
Global Tools
Local installation of .NET global tools is fully supported and preferred when possible - more info in the Microsoft docs.
For globally installing .NET tools, search if they are available as Nix packages - they are packaged as any other normal
.NET binary, using buildDotnetModule. For .NET tools with no source available, or those hard to build from source, buildDotnetGlobalTool is available. See dotnet nixpkgs manual for more info.
Note that Nix-packaged .NET tools use a special wrapper (toggled by useDotnetFromEnv option in buildDotnetModule) that automatically picks up .NET install from the user environment. If you want to use a
different SDK version with a Nix-packaged .NET tools than the default, make sure the dotnet CLI of your wanted SDK version is installed and available.
Packaging
.NET packages can be built with buildDotnetModule
More information about buildDotnetModule can be found in the nixpkgs manual
Example build file:
{
buildDotnetModule,
dotnetCorePackages,
}:
buildDotnetModule {
pname = "hello";
version = "0.1";
src = ./.;
projectFile = "Hello/Hello.csproj";
dotnet-sdk = dotnetCorePackages.sdk_8_0;
dotnet-runtime = dotnetCorePackages.runtime_8_0;
nugetDeps = ./deps.json;
}
If the fetch-deps script isn't working for whatever reason, you can manually run nuget-to-json:
$ dotnet restore --packages=packageDir ./SomeProject.csproj
$ nuget-to-json packageDir > deps.json
$ rm -r packageDir
Remember to build and run the fetch-deps script after NuGet packages are updated, or building the derivation will fail.
Building non-.NET Core packages
Keep in mind that building projects which don't use the .NET SDK (formerly the .NET Core SDK) and its dotnet CLI tool isn't supported.
For those projects, you'll have to heavily customise the buildDotnetModule build steps, or write a custom derivation.
Projects which target .NET Standard or .NET Framework (incl. Mono), but still use the new project structure and SDK, work as expected. Just remember to add `mono` to `buildInputs` and generate a wrapper script in `postInstall`.
Packaging ASP.NET projects
Currently building ASP.NET project as Nix package produces a website that does not work correctly out of the box because the executable can not find wwwroot, so all the static assets won't load with 404.
Request finished HTTP/2 GET https://my.app/css/site.css - 404 0
The situation can be fixed by setting WEBROOT environment variable to the package path.
An example of systemd + ASP.NET 8 service:
# myapp package needs to be imported; and added to `environment.systemPackages`
# the variable myapp is used below
systemd.services.my-app = {
enable = true;
description = "Runs my.app";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
# allow binding to privileged ports - when you want to expose Kestrel directly without reverse proxy
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
User = "myapp"; # must be created using users.users.myapp = { isSystemUser = true; group = "myapp"; };
Group = "myapp"; # must be created using users.groups.myapp = {};
Restart = "always";
ExecStart = "${myapp}/bin/myapp";
StateDirectory = "myapp";
StateDirectoryMode = "0750";
WorkingDirectory = "/var/lib/myapp";
# EnvironmentFile = "/var/lib/myapp/env";
};
environment = {
WEBROOT = "${myapp}/lib/myapp/wwwroot"; # IMPORTANT, required to pick up static assets
DOTNET_ENVIRONMENT = "Production";
# the following are examples
ConnectionStrings__DefaultConnection = "Host=/var/run/postgresql;Database=myapp";
# Kestrel + HTTPS; must setup https://wiki.nixos.org/wiki/ACME
Kestrel__Endpoints__Https__Url = "https://my.app";
Kestrel__Endpoints__Https__Certificate__Path = "/var/lib/acme/my.app/cert.pem";
Kestrel__Endpoints__Https__Certificate__KeyPath = "/var/lib/acme/my.app/key.pem";
Logging__LogLevel__Default = "Information";
Logging__LogLevel__Microsoft__AspNetCore = "Warning"; # this does not actually work, not sure how to fix
Authentication__Google__ClientId = "xxxyyyzzz.apps.googleusercontent.com";
Authentication__Microsoft__ClientId = "aaaaaa-0000-aaaa-0000-aaaaaaaaaa";
# secrets must be placed in /var/lib/myapp/appsettings.json
# TODO email
# TODO Stripe
Stripe__Currency = "USD";
};
};
See also: setting up SSL certificates using ACME
Examples
Running Rider with dotnet & PowerShell
Rider has better compatibility when run in FHS mode
Rider package
pkgs.jetbrains.rider
rider-fhs.nix
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSEnv {
name = "rider-env";
targetPkgs = pkgs: (with pkgs; [
dotnetCorePackages.dotnet_8.sdk
dotnetCorePackages.dotnet_8.aspnetcore
powershell
]);
multiPkgs = pkgs: (with pkgs; [
]);
runScript = "nohup rider &";
}).env
nix-shell ./rider-fhs.nix
This can be added as an alias to your shell if you update the reference to an absolute address, such as location within your home directory.
run-rider = "nix-shell ~/nix/rider-fhs.nix";Multi-SDK installation with local workload installation enabled
By default, workload installation will fail on NixOS, as dotnet will attempt to save it to $DOTNET_ROOT, which is inside the read-only Nix store.
Please visit the forum for an example of a multi-SDK installation with workload changed to install to home directory.
Troubleshooting
.NET location: Not found
If running a .NET-build executable you get the above error, make sure the DOTNET_ROOT environment variable is set:
environment.sessionVariables = {
DOTNET_ROOT = "${pkgs.dotnet-sdk}/share/dotnet/";
};
TargetFramework value was not recognized
error NETSDK1013: The TargetFramework value 'net6.0-windows' was not recognized. It may be misspelled. If not, then the TargetFrameworkIdentifier and/or TargetFrameworkVersion properties must be specified explicitly.
Wontfix: The project will build only on Windows.
Unable to find package
error NU1101: Unable to find package runtime.any.System.Collections. No packages exist with this id in source(s): nugetSource
Unsure what specific situations cause this, probably has something to do with .NET Standard libraries.
The workaround is modifying the bits that generate nuget-deps.nix:
dotnet restore --packages=packageDir --use-current-runtime ./SomeProject.csproj
nuget-to-nix packageDir >deps.nix
rm -r packageDir
The new parameter --use-current-runtime requires .NET SDK 8+. I believe what it does is explicitly adding packages missing in this runtime vs .NET Standard to packageDir.
If this still does not work, it might indicate a good time to update target frameworks and dependencies.
See also
- NixOS GitHub dotnet docs
- dotnet in the nixpkgs manual
- buildDotnetModule references in nixpkgs
- NixOS.NET community on Reddit
- NixOS.NET community on Discord
- The journey of packaging a .NET app on Nix
- https://en.wikipedia.org/wiki/.NET_Framework - The old, windows-only version of .NET. Newer versions (ie. .NET Core) are multiplatform.
- https://en.wikipedia.org/wiki/Mono_(software) is the open source reimplementation of .NET Framework. Its runtime/JIT has been merged into .NET Core, and now it only receives bugfixes.
- https://learn.microsoft.com/en-us/dotnet/core/introduction