DotNET: Difference between revisions

imported>Milahu
XML namespace error: how to replace xbuild with msbuild
m Use the correct command name.
 
(43 intermediate revisions by 16 users not shown)
Line 1: Line 1:
dotnet packages can be built with <code>buildDotnetPackage</code>
.NET packages can be built with <code>buildDotnetModule</code>


example build file:
More information about <code>buildDotnetModule</code> can be found in the [https://nixos.org/manual/nixpkgs/unstable/#dotnet nixpkgs manual]
Example build file:


<syntaxHighlight lang=nix>
<syntaxhighlight lang="nix" line="1" start="1">
/*
{
some_program/default.nix
  buildDotnetModule,
nix-build -E 'with import <nixpkgs> { }; callPackage ./default.nix { }'
  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;
}
 
</syntaxhighlight>
 
If the <code>fetch-deps</code> script isn't working for whatever reason, you can manually run <code>nuget-to-json</code>:
<syntaxhighlight lang="shell-session">
$ dotnet restore --packages=packageDir ./SomeProject.csproj
$ nuget-to-json packageDir > deps.json
$ rm -r packageDir
</syntaxhighlight>
 
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 ==
 
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.
For those projects, you'll have to heavily customise the <code>buildDotnetModule</code> 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 <code>wwwroot</code>, so all the static assets won't load with 404.
 
<blockquote>
Request finished HTTP/2 GET https://my.app/css/site.css - 404 0
</blockquote>
 
The situation can be fixed by setting <code>WEBROOT</code> environment variable to the package path.
 
An example of systemd + ASP.NET 8 service:


{ lib
<syntaxhighlight lang="nix">
, stdenv
# myapp package needs to be imported; and added to `environment.systemPackages`
, fetchFromGitHub
# the variable myapp is used below
, buildDotnetPackage
, dotnetPackages
, pkg-config
}:


buildDotnetPackage rec {
systemd.services.my-app = {
   pname = "some_program";
   enable = true;
   baseName = pname; # workaround for "called without baseName"
  description = "Runs my.app";
   version = "some_version";
   wantedBy = [ "multi-user.target" ];
   src = fetchFromGitHub {
  after = [ "network-online.target" ];
     owner = "some_owner";
   wants = [ "network-online.target" ];
     repo = pname;
   serviceConfig = {
     rev = "v${version}";
     # allow binding to privileged ports - when you want to expose Kestrel directly without reverse proxy
     sha256 = ""; # todo
    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";
   };
   };
   projectFile = ["path/to/some_project.csproj"];
   environment = {
  propagatedBuildInputs = [
    WEBROOT = "${myapp}/lib/myapp/wwwroot"; # IMPORTANT, required to pick up static assets
  ];
 
  buildInputs = [
    DOTNET_ENVIRONMENT = "Production";
     # unit tests
 
     dotnetPackages.NUnit
    # the following are examples
     dotnetPackages.NUnitRunners
    ConnectionStrings__DefaultConnection = "Host=/var/run/postgresql;Database=myapp";
  ];
 
  nativeBuildInputs = [
     # Kestrel + HTTPS; must setup https://wiki.nixos.org/wiki/ACME
     pkg-config
     Kestrel__Endpoints__Https__Url = "https://my.app";
  ];
     Kestrel__Endpoints__Https__Certificate__Path = "/var/lib/acme/my.app/cert.pem";
  meta = with lib; {
    Kestrel__Endpoints__Https__Certificate__KeyPath = "/var/lib/acme/my.app/key.pem";
     homepage = "some_homepage";
 
     description = "some_description";
     Logging__LogLevel__Default = "Information";
     license = licenses.mit;
    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";
   };
   };
}
};
</syntaxHighlight>
 
</syntaxhighlight>
 
See also: setting up SSL certificates using [[ACME]]
 
== .NET location: Not found ==
 
If running a .NET-build executable you get the above error, make sure the DOTNET_ROOT environment variable is set:
<syntaxhighlight lang="nix">
environment.sessionVariables = {
  DOTNET_ROOT = "${pkgs.dotnet-sdk}/share/dotnet/";
};
</syntaxhighlight>
 
See : https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables#net-sdk-and-cli-environment-variables


== XML namespace error ==
== TargetFramework value was not recognized ==


<blockquote>
<blockquote>
xbuild tool is deprecated and will be removed in future updates, use msbuild instead


<nowiki>
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.
The default XML namespace of the project must be the MSBuild XML namespace. If the project is authored in the MSBuild 2003 format, please add xmlns="http://schemas.microsoft.com/developer/msbuild/2003" to the <Project> element. If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  
 
</nowiki>
</blockquote>
</blockquote>


workaround: in <code>buildPhase</code>, replace <code>xbuild</code> with <code>msbuild</code>  
Wontfix: The project will build only on Windows.
 
== Unable to find package ==
 
<blockquote>
 
error NU1101: Unable to find package runtime.any.System.Collections. No packages exist with this id in source(s): nugetSource
 
</blockquote>
 
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:
 
<syntaxhighlight lang="sh">
dotnet restore --packages=packageDir --use-current-runtime ./SomeProject.csproj
nuget-to-nix packageDir >deps.nix
rm -r packageDir
</syntaxhighlight>
 
The new parameter <code>--use-current-runtime</code> 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.
 
== 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>
<syntaxHighlight lang=nix>
{ lib
with import <nixpkgs> {};
# ...
pkgs.mkShell rec {
, msbuild
 
}:
  dotnetPkg =
    (with dotnetCorePackages; combinePackages [
      sdk_7_0
    ]);


buildDotnetPackage rec {
   deps = [
   # ...
    zlib
  projectFile = "path/to/some_project.csproj";
    zlib.dev
  # ...
    openssl
  buildInputs = [
     dotnetPkg
     msbuild
   ];
   ];
   buildPhase = ''
 
     msbuild /p:Configuration=Release ${projectFile}
  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>
</syntaxHighlight>


== missing NuGet packages ==
== 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].


example error:
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.


<blockquote>
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
<code>
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.
<nowiki>
 
error : This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is ../../packages/Microsoft.Bcl.Build.1.0.21/build/Microsoft.Bcl.Build.targets.
 
</nowiki>
== Example: Running Rider with dotnet & PowerShell ==
</code>
Rider has better compatibility when run in FHS mode
</blockquote>
 
Rider package<syntaxhighlight lang="nix">
pkgs.jetbrains.rider
</syntaxhighlight>rider-fhs.nix<syntaxhighlight lang="nix">
{ pkgs ? import <nixpkgs> {} }:


these are upstream bugs
(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>


as workaround, patch all <code>*.csproj</code> files, to remove all XML tags that contain the "missing file" paths, for example
== Example: multi-SDK installation with local workload installation enabled ==


<blockquote>
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.
<code>
&lt;Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" /&gt;
</code>
</blockquote>


see also https://stackoverflow.com/questions/32254439/nuget-packages-are-missing
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.


== See also ==
== See also ==


* [https://ryantm.github.io/nixpkgs/languages-frameworks/dotnet/ dotnet in the nixpkgs manual]
* [https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/dotnet.section.md NixOS GitHub dotnet docs]
* [https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/dotnet-packages.nix nixpkgs/pkgs/top-level/dotnet-packages.nix] &rarr; look for "SOURCE PACKAGES"
* [https://nixos.org/manual/nixpkgs/unstable/#dotnet dotnet in the nixpkgs manual]
* [https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/dotnet/build-dotnet-package/default.nix buildDotnetPackage implementation]
* [https://github.com/search?q=repo%3ANixOS%2Fnixpkgs%20buildDotnetModule&type=code buildDotnetModule references in nixpkgs]
* [https://grep.app/search?q=buildDotnetPackage&filter%5Brepo%5D%5B0%5D=NixOS/nixpkgs&filter%5Blang%5D%5B0%5D=Nix&filter%5Bpath%5D%5B0%5D=pkgs/ buildDotnetPackage references in nixpkgs]
* [https://www.reddit.com/r/NixOS_dotnet NixOS.NET community on Reddit]
* https://en.wikipedia.org/wiki/.NET_Framework
* [https://discord.gg/pTpq7Qfs NixOS.NET community on Discord]
** https://en.wikipedia.org/wiki/List_of_CLI_languages: C#, [[Fsharp|F#]], Visual Basic, ...
* [https://sgt.hootr.club/molten-matter/dotnet-on-nix/ The journey of packaging a .NET app on Nix]
** https://en.wikipedia.org/wiki/Mono_(software) is the open source implementation of the DotNET compiler and runtime
* 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
 
 
[[Category:Languages]]