« Asp.net core 7 » : différence entre les versions
(71 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 6 : | Ligne 6 : | ||
* [https://docs.microsoft.com/en-us/aspnet/core Doc Microsoft] | * [https://docs.microsoft.com/en-us/aspnet/core Doc Microsoft] | ||
* [[:Catégorie:.NET_Core|Catégorie .NET Core]] | * [[:Catégorie:.NET_Core|Catégorie .NET Core]] | ||
* [[Blazor_ASP.NET_Core_7.0|Blazor]] | |||
* [[Asp.net_core_web_api|Web API]] | |||
= dotnet CLI = | = dotnet CLI = | ||
Ligne 69 : | Ligne 71 : | ||
</filebox> | </filebox> | ||
= [https:// | = [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0 Configuration] = | ||
Sources des settings par défaut dans l'ordre de lecture: | Sources des settings par défaut dans l'ordre de lecture: | ||
# {{boxx|appsettings.json}} | # {{boxx|appsettings.json}} | ||
Ligne 101 : | Ligne 103 : | ||
</filebox> | </filebox> | ||
== appsettings.json == | == [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0#appsettingsjson appsettings.json] == | ||
<filebox fn='appsettings.json'> | <filebox fn='appsettings.json'> | ||
{ | { | ||
Ligne 141 : | Ligne 143 : | ||
</filebox> | </filebox> | ||
== [https:// | == [https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-7.0&tabs=linux Safe storage of app secrets in development in ASP.NET Core] == | ||
* [https://dotnetcore.gaprogman.com/2017/09/07/user-secrets-what-are-they-and-why-do-i-need-them/ User Secrets – What Are They And Why Do I Need Them?] | * [https://dotnetcore.gaprogman.com/2017/09/07/user-secrets-what-are-they-and-why-do-i-need-them/ User Secrets – What Are They And Why Do I Need Them?] | ||
Useful in dev environment to not store password in source code. | Useful in dev environment to not store password in source code. | ||
Ligne 198 : | Ligne 200 : | ||
</filebox> | </filebox> | ||
== [https:// | == [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0#non-prefixed-environment-variables Non-prefixed environment variables] == | ||
<filebox fn='/etc/systemd/system/kestrel-myapp.service' lang='ini'> | |||
Environment=ConnectionStrings__MyApp=server\x3dlocalhost\x3bdatabase\x3dMyDb\x3buser\x3dMyUser\x3bpassword\x3dMyPwd | |||
Environment=SqlServerVersion=10.10.5-MariaDB | |||
</filebox> | |||
== [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#command-line Command-line] == | == [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#command-line Command-line] == | ||
Ligne 260 : | Ligne 265 : | ||
</filebox> | </filebox> | ||
= [https:// | = [https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli Publish] = | ||
== [https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli#framework-dependent-executable Framework-dependent executable] == | |||
Creates a platform-specific executable with only the application binaries and its dependencies. | |||
{{ListPlusMinus|type=plus|list= | |||
* lighter deployment: only the application binaries and its dependencies are deployed | |||
* the .NET runtime security updates are managed by the system | |||
}} | |||
{{ListPlusMinus|type=minus|list= | |||
* the required .NET runtime of the application has to match the installed .NET runtime | |||
}} | |||
<kode lang='bash'> | <kode lang='bash'> | ||
dotnet publish -c Release -r linux-arm64 --self-contained false | |||
dotnet publish -c Release -r linux- | |||
# -c : configuration : Debug (default), Release | # -c : configuration : Debug (default), Release | ||
# -r <RUNTIME_IDENTIFIER> : publishes the application for a given runtime | # -r <RUNTIME_IDENTIFIER> : publishes the application for a given runtime | ||
# --self-contained [true|false] : publishes the .NET Core runtime with the application (default true if a runtime identifier is specified and the project is an executable project) | # --self-contained [true|false] : publishes the .NET Core runtime with the application (default true if a runtime identifier is specified and the project is an executable project) | ||
# -o /path/folder : output directory (default: | # -o /path/folder : output directory (default: bin/[configuration]/[framework]/[runtime]/publish ) | ||
</kode> | </kode> | ||
* [https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish dotnet publish] | * [https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish dotnet publish] | ||
[https://docs.microsoft.com/en-us/dotnet/core/rid-catalog RID Catalog] ([https://github.com/dotnet/runtime/blob/master/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.json list]): {{boxx|linux-arm64}}, {{boxx|linux-x64}}, {{boxx|win10-x64}} | |||
== [https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli#self-contained-deployment Self-contained deployment] == | |||
Creates a platform-specific executable with the application binaries, its dependencies and the required .NET runtime. | |||
{{ListPlusMinus|type=plus|list= | |||
* runs on hosts which doesn't have the .NET runtime installed | |||
</ | }} | ||
{{ListPlusMinus|type=minus|list= | |||
* bigger deployment | |||
* doesn't follow the .NET security updates | |||
}} | |||
<kode lang='bash'> | |||
dotnet publish -c Release -r linux-arm64 --self-contained true -p:PublishTrimmed=true | |||
# -c : configuration : Debug (default), Release | |||
# -r <RUNTIME_IDENTIFIER> : publishes the application for a given runtime | |||
# -o /path/folder : output directory (default: bin/[configuration]/[framework]/[runtime]/publish ) | |||
</kode> | |||
* [https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained Trim self-contained deployments and executables] | |||
[https:// | === [https://github.com/dotnet/aspnetcore/issues/40033 Bug MissingMethodException occured when deploying Blazor Server app with 'Trim Unused code'] === | ||
<pre> | |||
System.MissingMethodException: Cannot dynamically create an instance of type 'Microsoft.AspNetCore.Components.Web.HeadOutlet'. | |||
Reason: No parameterless constructor defined. | |||
</pre> | |||
<filebox fn='App.razor'> | |||
@using System.Diagnostics.CodeAnalysis; | |||
@code { | |||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(HeadOutlet))] // Prevent HeadOutlet from being trimmed | |||
protected override void OnInitialized() { } | |||
} | |||
</filebox> | </filebox> | ||
== Linux == | == Linux == | ||
Ligne 324 : | Ligne 339 : | ||
Environment=ASPNETCORE_URLS=http://localhost:5001 | Environment=ASPNETCORE_URLS=http://localhost:5001 | ||
Environment=ConnectionStrings__MyConnectionString=server\x3dlocalhost\x3bdatabase\x3dMyDb\x3buser\x3dMyUser\x3bpassword\x3dMyPwd | Environment=ConnectionStrings__MyConnectionString=server\x3dlocalhost\x3bdatabase\x3dMyDb\x3buser\x3dMyUser\x3bpassword\x3dMyPwd | ||
Environment=SqlServerVersion=10.10.5-MariaDB | |||
Environment=MyWebapiUrl=http://localhost:5002 | |||
[Install] | [Install] | ||
Ligne 371 : | Ligne 388 : | ||
= Git = | = Git = | ||
<filebox fn='.gitignore' lang='bash'> | <filebox fn='.gitignore' lang='bash'> | ||
# Build | # Build folders | ||
bin/ | bin/ | ||
obj/ | obj/ | ||
# . | # Visual Studio local state folder | ||
.vs/ | |||
</filebox> | </filebox> | ||
= [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0 Log] = | = [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0 Log] = | ||
{{ | {{info | By default, an app is logging into {{boxx|Console}}, {{boxx|Debug}}, {{boxx|EventSource}}, {{boxx|EventLog}} (only when running on Windows).<br> | ||
This include the linux journal for production and the VS code DEBUG CONSOLE for development.}} | |||
By default, an app is logging into {{boxx|Console}}, {{boxx|Debug}}, {{boxx|EventSource}}, {{boxx|EventLog}} (only when running on Windows). | |||
< | |||
<kode lang='cs'> | <kode lang='cs'> | ||
Ligne 412 : | Ligne 412 : | ||
public void MyMethod() | public void MyMethod() | ||
{ | { | ||
logger.LogDebug("Debug"); | // to optimize the performances, test if the log level is enabled | ||
if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug("Debug"); | |||
logger.LogTrace("Trace"); | logger.LogTrace("Trace"); | ||
logger.LogInformation("Info"); | logger.LogInformation("Info"); | ||
Ligne 422 : | Ligne 423 : | ||
</kode> | </kode> | ||
<filebox fn=' | <filebox fn='appsettings.json'> | ||
{ | { | ||
"Logging": { | "Logging": { | ||
"LogLevel": { | "LogLevel": { | ||
"Default": "Information", | "Default": "Information", // log level par défaut | ||
"Microsoft": "Warning", | "Microsoft": "Warning", // pour les loggers commençant par Microsoft | ||
"MyClass": "Debug" | "MyNamespace.MyClass": "Debug" // pour les loggers de MyClass | ||
} | } | ||
} | } | ||
</filebox> | </filebox> | ||
<filebox fn='Program.cs' collapsed> | |||
public static IHostBuilder CreateHostBuilder(string[] args) => | |||
Host.CreateDefaultBuilder(args) | |||
.ConfigureLogging(logging => | |||
{ | |||
logging.ClearProviders(); // remove all the providers: no more logs | |||
}) | |||
.ConfigureWebHostDefaults(webBuilder => | |||
{ | |||
webBuilder.UseStartup<Startup>(); | |||
}); | |||
</filebox> | |||
{{warn | 1=The Log methods are [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0#no-asynchronous-logger-methods synchronous].<br> | |||
There is no file log provider.}} | |||
== [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging#built-in-logging-providers Built-in logging providers] == | == [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging#built-in-logging-providers Built-in logging providers] == | ||
Ligne 481 : | Ligne 498 : | ||
dotnet sln add ./MyService.Tests/MyService.Tests.csproj | dotnet sln add ./MyService.Tests/MyService.Tests.csproj | ||
# run the unit tests | # run all the unit tests | ||
dotnet test | dotnet test | ||
# run the unit tests of a specific namespace / class | |||
dotnet test --filter Namespace.Class | |||
</kode> | </kode> | ||
= [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-7 Code analysis] = | = [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-7 Code analysis] = | ||
* [https://editorconfig.org/ editorconfig] | |||
== Code quality analysis == | == Code quality analysis == | ||
Those [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-7#enabled-rules rules] are enabled by default.<br> | Those [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-7#enabled-rules rules] are enabled by default.<br> | ||
Ligne 491 : | Ligne 512 : | ||
<filebox fn='MyProject.csproj' lang='xml'> | <filebox fn='MyProject.csproj' lang='xml'> | ||
<PropertyGroup> | <PropertyGroup> | ||
<AnalysisLevel>latest- | <AnalysisLevel>latest-recommended</AnalysisLevel> | ||
</PropertyGroup> | </PropertyGroup> | ||
</filebox> | |||
* [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ Code quality rules CAxxxx] | |||
{{info | Prefer the use of {{boxx|editorconfig}} to {{boxx|globalconfig}}}} | |||
<filebox fn='.globalconfig' lang='ini' collapsed> | |||
# Top level entry required to mark this as a global AnalyzerConfig file | |||
is_global = true | |||
# NOTE: No section headers for configuration entries | |||
#### .NET Coding Conventions #### | |||
# this. and Me. preferences | |||
dotnet_style_qualification_for_method = true:warning | |||
#### Diagnostic configuration #### | |||
# CA2007: Do not directly await a Task | |||
dotnet_diagnostic.CA2007.severity = none | |||
</filebox> | </filebox> | ||
Ligne 506 : | Ligne 547 : | ||
* [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-files#global-analyzerconfig Configuration files for code analysis rules] | * [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-files#global-analyzerconfig Configuration files for code analysis rules] | ||
* [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options#example-editorconfig-file An example of .editorconfig file with the default options] | * [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options#example-editorconfig-file An example of .editorconfig file with the default options] | ||
* [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules Code-style rules IDExxxx] | |||
* [[Encodage_de_caractères#Convertion|Change encoding]] | |||
<filebox fn='.editorconfig' lang='ini' collapsed> | <filebox fn='.editorconfig' lang='ini' collapsed> | ||
############################### | ############################### | ||
Ligne 515 : | Ligne 559 : | ||
[*] | [*] | ||
charset = utf-8 | charset = utf-8 | ||
############################### | ############################### | ||
# | # Analyzer configuration # | ||
############################### | ############################### | ||
# set the rules severity to warning | # set the rules severity to warning | ||
dotnet_analyzer_diagnostic.severity = warning | dotnet_analyzer_diagnostic.severity = warning | ||
############################### | |||
# Code Quality configuration # | |||
############################### | |||
[*.cs] | |||
# CA1826: Use property instead of Linq Enumerable method | |||
# Exclude FirstOrDefault and LastOrDefault methods | |||
dotnet_code_quality.CA1826.exclude_ordefault_methods = true | |||
############################### | |||
# Style configuration # | |||
############################### | |||
# IDE0003 / IDE0009: this and Me preferences | |||
dotnet_style_qualification_for_field = true | |||
# IDE0007 / IDE0008: 'var' preferences | |||
csharp_style_var_for_built_in_types = true | |||
csharp_style_var_when_type_is_apparent = true | |||
csharp_style_var_elsewhere = true : silent | |||
# IDE0011: Add braces | |||
csharp_prefer_braces = when_multiline | |||
# IDE0022: Use expression body for methods | |||
csharp_style_expression_bodied_methods = when_on_single_line | |||
# IDE0160 / IDE0161: Namespace declaration preferences | |||
csharp_style_namespace_declarations = file_scoped | |||
############################### | |||
# Disabled rules # | |||
############################### | |||
# IDE0046: Use conditional expression for return | |||
dotnet_diagnostic.IDE0046.severity = suggestion | |||
# IDE0058: Remove unnecessary expression value | |||
dotnet_diagnostic.IDE0058.severity = none | |||
# CA1305: Specify IFormatProvider | |||
dotnet_diagnostic.CA1305.severity = none | |||
# CA1310: Specify StringComparison for correctness | |||
dotnet_diagnostic.CA1310.severity = none | |||
############################### | ############################### | ||
Ligne 549 : | Ligne 638 : | ||
dotnet_naming_rule.parameters_should_be_camel_case.style = camel_case_style | dotnet_naming_rule.parameters_should_be_camel_case.style = camel_case_style | ||
dotnet_naming_rule.parameters_should_be_camel_case.severity = warning | dotnet_naming_rule.parameters_should_be_camel_case.severity = warning | ||
</filebox> | </filebox> | ||
Ligne 568 : | Ligne 645 : | ||
"omnisharp.enableEditorConfigSupport": true, | "omnisharp.enableEditorConfigSupport": true, | ||
</filebox> | </filebox> | ||
== Visual Studio == | |||
=== [https://learn.microsoft.com/en-us/visualstudio/code-quality/configure-live-code-analysis-scope-managed-code?view=vs-2022#custom-analysis-scope Set the scope of live code analysis] === | |||
# Tools → Options | |||
# Text Editor → C# → Advanced | |||
## Run background code analysis for: Current document | |||
## Show compiler errors and warnings for: Open documents | |||
== [https://github.com/josefpihrt/roslynator Roslynator] == | == [https://github.com/josefpihrt/roslynator Roslynator] == | ||
Ligne 573 : | Ligne 657 : | ||
# Configure Roslynator on a user-wide basis | # Configure Roslynator on a user-wide basis | ||
## vscode → Ctrl + Shift + P → enter roslynator → select Roslynator: Open Default Configuration File (.roslynatorconfig) | ## vscode → Ctrl + Shift + P → enter roslynator → select Roslynator: Open Default Configuration File (.roslynatorconfig) | ||
<filebox fn='~/.local/share/JosefPihrt/Roslynator/.roslynatorconfig' lang='ini'> | * [https://github.com/JosefPihrt/Roslynator/tree/main/docs/analyzers Analyzers RCSxxxx] | ||
<filebox fn='~/.local/share/JosefPihrt/Roslynator/.roslynatorconfig' lang='ini' collapsed> | |||
is_global = true | is_global = true | ||
Ligne 580 : | Ligne 666 : | ||
dotnet_analyzer_diagnostic.category-roslynator.severity = warning | dotnet_analyzer_diagnostic.category-roslynator.severity = warning | ||
# | # enable all refactorings | ||
roslynator_refactorings.enabled = true | |||
# enable all compiler diagnostic fixes | |||
roslynator_compiler_diagnostic_fixes.enabled = true | |||
# Options | |||
roslynator_accessibility_modifiers = explicit | |||
roslynator_accessor_braces_style = single_line_when_expression_is_on_single_line | |||
roslynator_array_creation_type_style = implicit_when_type_is_obvious | |||
roslynator_arrow_token_new_line = before | |||
roslynator_binary_operator_new_line = before | |||
roslynator_blank_line_after_file_scoped_namespace_declaration = true | |||
roslynator_blank_line_between_closing_brace_and_switch_section = false | |||
roslynator_blank_line_between_single_line_accessors = false | |||
roslynator_blank_line_between_using_directives = never | |||
roslynator_block_braces_style = single_line_when_empty | |||
#roslynator_body_style = block|expression | |||
roslynator_conditional_operator_condition_parentheses_style = omit | |||
roslynator_conditional_operator_new_line = beforeroslynator_configure_await = false | |||
roslynator_doc_comment_summary_style = multi_line | |||
roslynator_empty_string_style = field | |||
roslynator_enum_flag_value_style = decimal_number | |||
roslynator_enum_has_flag_style = method | |||
roslynator_equals_token_new_line = before | |||
roslynator_infinite_loop_style = while | |||
roslynator_max_line_length = 140 | |||
roslynator_new_line_at_end_of_file = false | |||
roslynator_new_line_before_while_in_do_statement = false | |||
roslynator_null_conditional_operator_new_line = before | |||
roslynator_null_check_style = pattern_matching | |||
roslynator_object_creation_parentheses_style = omit | |||
roslynator_object_creation_type_style = implicit_when_type_is_obvious | |||
roslynator_prefix_field_identifier_with_underscore = false | |||
roslynator_suppress_unity_script_methods = true | |||
roslynator_use_anonymous_function_or_method_group = method_group | |||
roslynator_use_block_body_when_declaration_spans_over_multiple_lines = true | |||
roslynator_use_block_body_when_expression_spans_over_multiple_lines = true | |||
roslynator_use_var_instead_of_implicit_object_creation = true | |||
# Analyzers | |||
# Add blank line between single-line declarations | # Add blank line between single-line declarations | ||
dotnet_diagnostic.rcs0012.severity = none | dotnet_diagnostic.rcs0012.severity = none | ||
Ligne 587 : | Ligne 713 : | ||
# Use explicit type instead of 'var' (when the type is not obvious) | # Use explicit type instead of 'var' (when the type is not obvious) | ||
dotnet_diagnostic.rcs1008.severity = none | dotnet_diagnostic.rcs1008.severity = none | ||
# Use explicit type instead of 'var' (foreach variable) | |||
dotnet_diagnostic.rcs1009.severity = none | |||
# Use explicit type instead of 'var' (when the type is obvious) | # Use explicit type instead of 'var' (when the type is obvious) | ||
dotnet_diagnostic.rcs1012.severity = none | dotnet_diagnostic.rcs1012.severity = none | ||
# Avoid unnecessary boxing of value type | |||
dotnet_diagnostic.rcs1198.severity = none | |||
# Mark publicly visible type with DebuggerDisplay attribute | # Mark publicly visible type with DebuggerDisplay attribute | ||
dotnet_diagnostic.rcs1223.severity = none | dotnet_diagnostic.rcs1223.severity = none | ||
Ligne 598 : | Ligne 728 : | ||
dotnet tool install -g roslynator.dotnet.cli | dotnet tool install -g roslynator.dotnet.cli | ||
roslynator | roslynator analyze \ | ||
--analyzer-assemblies \ | --analyzer-assemblies \ | ||
~/.vscode/extensions/josefpihrt-vscode.roslynator-4.3.0/roslyn/common \ | ~/.vscode/extensions/josefpihrt-vscode.roslynator-4.3.0/roslyn/common \ | ||
Ligne 614 : | Ligne 744 : | ||
</kode> | </kode> | ||
}} | }} | ||
== Code coverage == | |||
* [https://reportgenerator.io/ ReportGenerator] | |||
<kode lang='bash'> | |||
# add the XunitXML.TestLogger nuget package to the unit test project | |||
dotnet add package XunitXML.TestLogger | |||
# run unit tests with Coverlet data collector and log the results | |||
dotnet test MySolution.sln --collect="XPlat Code Coverage" --logger:"xunit;LogFilePath=TestResults.xml" | |||
# creates a TestResults.xml report and a TestResults/[guid]/coverage.cobertura.xml report | |||
# extract the line coverage: | |||
xmllint --xpath "string(/coverage/@line-rate)" TestResults/[guid]/coverage.cobertura.xml | |||
sed -n -r 's/<coverage line-rate="([0-9.]+)".*/\1/p' TestResults/[guid]/coverage.cobertura.xml | |||
# install the ReportGenerator tool | |||
dotnet tool install -g dotnet-reportgenerator-globaltool | |||
# get a text summary report from all the cobertura reports | |||
reportgenerator -reports:"*/TestResults/*/coverage.cobertura.xml" -targetdir:CoverageReport -reporttypes:TextSummary | |||
# creates CoverageReport/TextSummary.txt | |||
# extract the line coverage: | |||
sed -n -r 's/Line coverage: ([0-9.]+)%/\1/p' CoverageReport/Summary.txt | |||
</kode> | |||
== Ignore generated code == | |||
Create an {{boxx|.editorconfig}} file in a folder to not run code analysis on the files of this folder. | |||
<filebox fn='MyWebapi/DataAccess/.editorconfig' lang='ini'> | |||
[*] | |||
generated_code = true | |||
dotnet_analyzer_diagnostic.severity = silent | |||
</filebox> | |||
= ARM = | = ARM = | ||
Ligne 640 : | Ligne 800 : | ||
* MVC et Web API, plus de WebForm | * MVC et Web API, plus de WebForm | ||
[[File:ASP.NET_Core.jpg|800px]] | [[File:ASP.NET_Core.jpg|800px]] | ||
= [https://learn.microsoft.com/en-us/aspnet/core/migration/60-70?view=aspnetcore-7.0&tabs=visual-studio-code Migrate from ASP.NET Core 6.0 to 7.0] = | |||
<filebox fn='MyProject.csproj' lang='xml'> | |||
<!-- <TargetFramework>net6.0</TargetFramework> --> | |||
<TargetFramework>net7.0</TargetFramework> | |||
</filebox> | |||
= Installation = | = Installation = | ||
Ligne 663 : | Ligne 829 : | ||
== [[Ubuntu_arm_18.04#Installation|Ubuntu ARM]] == | == [[Ubuntu_arm_18.04#Installation|Ubuntu ARM]] == | ||
= Errors = | |||
== Failed to bind to address http://127.0.0.1:xxxx: address already in use == | |||
<kode lang='bash'> | |||
lsof -i :xxxx | |||
kill -9 [PID] | |||
</kode> |
Dernière version du 27 novembre 2023 à 00:37
Links
- What's new in ASP.NET Core 7.0
- .NET Core Release Notes
- Safe storage of app secrets
- Doc Microsoft
- Catégorie .NET Core
- Blazor
- Web API
dotnet CLI
# help dotnet -h # get versions of .NET SDK, Host, .NET runtimes installed dotnet --info # list available templates (webapi, blazor) dotnet new # create a new Web API project dotnet new webapi -o [project-name] --no-https # create a solution file and folder dotnet new sln --name MySolution # add a project to the solution dotnet sln add ./MyProject/MyProject.csproj # add a reference to another project dotnet add reference ../otherproject/otherproject.csproj # restore and build dotnet build # restore, build and run dotnet run # force url and port (default: http://127.0.0.1:5000) ASPNETCORE_URLS="http://127.0.0.1:5123" dotnet run # linux dotnet run --ASPNETCORE_ENVIRONMENT Development # powershell $env:ASPNETCORE_URLS="http://127.0.0.1:5123" ; dotnet run # powershell |
Nuget packages
# ajouter un package NuGet dotnet add package <package_name> dotnet add package <package_name> --version 2.0.0 # lists the NuGet packages dotnet list package # lists packages that have newer versions available dotnet list package --outdated # supprimer un package dotnet remove package <package_name> |
Directory.Build.targets
Allows you to manage the versions of Nuget packages in a single centralized file.
Directory.Build.targets |
<!-- Directory.Build.targets file has to be at the solution root --> <Project> <ItemGroup> <PackageReference Update="AutoMapper" Version="10.1.1" /> |
MyProject/MyProject.csproj |
<Project Sdk="Microsoft.NET.Sdk.Web"> <ItemGroup> <!-- remove the version --> <PackageReference Include="AutoMapper" /> |
Configuration
Sources des settings par défaut dans l'ordre de lecture:
- appsettings.json
- appsettings.<EnvironmentName>.json
- UserSecrets in Development environment
- Environment variables
- Command-line arguments
Les settings de la source suivante écrasent ceux déjà chargés. |
Startup.cs |
using Microsoft.Extensions.Configuration; // Microsoft.Extensions.Configuration.Abstractions.dll public IConfiguration Configuration { get; } public Startup(IConfiguration configuration) { Configuration = configuration; } // recherche Key, si Key n'a pas été trouvé affecte default value à la variable value var value = Configuration.GetValue<string>("Key", "default value"); var value = Configuration["Key"]; // pour les connection strings Configuration.GetConnectionString("SqlServer1") // dotnet add package System.Data.SqlClient var builder = new SqlConnectionStringBuilder(Configuration.GetConnectionString("SqlServer4")); // from appsettings.json builder.Password = Configuration["DbPassword"]; // from secrets storage in Dev and appsettings.json in Prod var connectionString = builder.ConnectionString; |
appsettings.json
appsettings.json |
{ "Key": "Value", "ConnectionStrings": { "SqlServer1": "Server=(localdb)\\MSSQLLocalDB;Database=MyDb;Integrated Security=True;MultipleActiveResultSets=True", "SqlServer2": "Server=(localdb)\\mssqllocaldb;Database=MyDb;Trusted_Connection=True;", "SqlServer3": "Server=localhost;Database=MyDb;User=sa;Password=pwd;", "SqlServer4": "server=localhost;database=MyDb;user=sa;", "MySql": "Server=localhost;Database=MyDb;User=root;Password=pwd;", "Sqlite": "Data Source=MyDb.db" }, "DbPassword": "****" } |
File Configuration Provider
Useful for using a file other than appsettings.config or for Console projects.
Program.cs |
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureHostConfiguration(configHost => { configHost.SetBasePath(Directory.GetCurrentDirectory()); configHost.AddJsonFile("passwords.json", optional: true); }) .UseStartup<Startup>(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config.AddJsonFile("passwords.json", optional: false, reloadOnChange: false); config.AddXmlFile("appsettings.xml", optional: true, reloadOnChange: true); }) .UseStartup<Startup>(); } |
Safe storage of app secrets in development in ASP.NET Core
Useful in dev environment to not store password in source code.
# aller dans le dossier contenant le *.csproj cd MyProject # adds a UserSecretsId element within a PropertyGroup of the .csproj file dotnet user-secrets init # set a secret # put a space as first character so the command line is not saved in the history dotnet user-secrets set "key" "secret" # the whole connection string dotnet user-secrets set "ConnectionStrings:SqlServer" "server=localhost;database=test;user=test;password=****" # only the connection string password dotnet user-secrets set "DbPassword" "****" # the secrets are stored in a JSON configuration file in a system-protected user profile folder on the local machine # Windows: %APPDATA%\microsoft\UserSecrets\<userSecretsId>\secrets.json # Linux: ~/.microsoft/usersecrets/<userSecretsId>/secrets.json # list all secrets of the current project dotnet user-secrets list # remove a secret in the current project dotnet user-secrets remove "key" # remove all secrets of the current project dotnet user-secrets clear |
WebApi/Program.cs |
// The user secrets configuration source is automatically added in development mode // when the project calls CreateDefaultBuilder to initialize a new instance of the host with preconfigured defaults. // CreateDefaultBuilder calls AddUserSecrets when the EnvironmentName is Development public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); |
Console/Program.cs |
public static IConfigurationRoot Configuration { get; set; } private static void Main() { var builder = new ConfigurationBuilder(); // dotnet add package Microsoft.Extensions.Configuration.UserSecrets builder.AddUserSecrets<Program>(); Configuration = builder.Build(); |
Non-prefixed environment variables
/etc/systemd/system/kestrel-myapp.service |
Environment=ConnectionStrings__MyApp=server\x3dlocalhost\x3bdatabase\x3dMyDb\x3buser\x3dMyUser\x3bpassword\x3dMyPwd Environment=SqlServerVersion=10.10.5-MariaDB |
Command-line
dotnet MyApp MyKey="value" |
Environnement
L’environnement utilisé est contenu dans la variable environnement ASPNETCORE_ENVIRONMENT 3 valeurs sont supportées par le framework:
- Development
- Staging
- Production (valeur par défaut)
# lancer le service avec l'environnement Development ASPNETCORE_ENVIRONMENT=Development dotnet run dotnet run --ASPNETCORE_ENVIRONMENT Development |
Configuration pour la ligne de commande:
Properties/launchSettings.json |
{ "profiles": { "my_project": { "commandName": "Project", "launchBrowser": true, "launchUrl": "api/values", "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } |
Configuration pour vs code:
.vscode/launch.json |
"configurations": [ { "name": ".NET Core Launch (web)", "env": { "ASPNETCORE_ENVIRONMENT": "Development" } } ] |
Configuration pour vs:
VS → Projet Properties → Debug → Environment variables → ASPNETCORE_ENVIRONMENT = Development
Deployment Scripts
MyProject.csproj |
<Target Name="MyPublishScripts" AfterTargets="BeforePublish"> <Exec Command="npm install" /> <Exec Command="gulp minify" /> <Exec Command="ng build" /> </Target> |
Publish
Framework-dependent executable
Creates a platform-specific executable with only the application binaries and its dependencies.
- lighter deployment: only the application binaries and its dependencies are deployed
- the .NET runtime security updates are managed by the system
- the required .NET runtime of the application has to match the installed .NET runtime
dotnet publish -c Release -r linux-arm64 --self-contained false # -c : configuration : Debug (default), Release # -r <RUNTIME_IDENTIFIER> : publishes the application for a given runtime # --self-contained [true|false] : publishes the .NET Core runtime with the application (default true if a runtime identifier is specified and the project is an executable project) # -o /path/folder : output directory (default: bin/[configuration]/[framework]/[runtime]/publish ) |
RID Catalog (list): linux-arm64, linux-x64, win10-x64
Self-contained deployment
Creates a platform-specific executable with the application binaries, its dependencies and the required .NET runtime.
- runs on hosts which doesn't have the .NET runtime installed
- bigger deployment
- doesn't follow the .NET security updates
dotnet publish -c Release -r linux-arm64 --self-contained true -p:PublishTrimmed=true # -c : configuration : Debug (default), Release # -r <RUNTIME_IDENTIFIER> : publishes the application for a given runtime # -o /path/folder : output directory (default: bin/[configuration]/[framework]/[runtime]/publish ) |
Bug MissingMethodException occured when deploying Blazor Server app with 'Trim Unused code'
System.MissingMethodException: Cannot dynamically create an instance of type 'Microsoft.AspNetCore.Components.Web.HeadOutlet'. Reason: No parameterless constructor defined.
App.razor |
@using System.Diagnostics.CodeAnalysis; @code { [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(HeadOutlet))] // Prevent HeadOutlet from being trimmed protected override void OnInitialized() { } } |
Linux
Service file
/etc/systemd/system/kestrel-myproject.service |
[Unit] Description=My Project description [Service] WorkingDirectory=/srv/myproject ExecStart=/srv/myproject/myproject ExecStart=/usr/bin/dotnet /srv/myproject/myproject.dll Restart=always RestartSec=10 # Restart service after 10 seconds if dotnet service crashes KillSignal=SIGINT SyslogIdentifier=myproject User=http Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false Environment=ASPNETCORE_URLS=http://localhost:5001 Environment=ConnectionStrings__MyConnectionString=server\x3dlocalhost\x3bdatabase\x3dMyDb\x3buser\x3dMyUser\x3bpassword\x3dMyPwd Environment=SqlServerVersion=10.10.5-MariaDB Environment=MyWebapiUrl=http://localhost:5002 [Install] WantedBy=multi-user.target |
# escape value as connection string systemd-escape "<value-to-escape>" |
Version
MyProject.csproj |
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <AssemblyVersion>1.1.1.1</AssemblyVersion> <FileVersion>2.2.2.2</FileVersion> <Version>3.3.3.3-xyz</Version> </PropertyGroup> </Project> |
typeof(Startup).Assembly.GetName().Version; // 1.1.1.1 Assembly.GetEntryAssembly().GetName().Version; // 1.1.1.1 Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version; // 2.2.2.2 Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; // 3.3.3.3-xyz |
Nuget
# Display locals for all folders dotnet nuget locals all --list # http-cache: /home/[user]/.local/share/NuGet/http-cache # global-packages: /home/[user]/.nuget/packages/ # temp: /tmp/NuGetScratch # plugins-cache: /home/[user]/.local/share/NuGet/plugin-cache # Clear all caches dotnet nuget locals all --clear # Clear the global packages folder dotnet nuget locals global-packages --clear |
Git
.gitignore |
# Build folders bin/ obj/ # Visual Studio local state folder .vs/ |
Log
By default, an app is logging into Console, Debug, EventSource, EventLog (only when running on Windows). This include the linux journal for production and the VS code DEBUG CONSOLE for development. |
public class MyClass { private readonly ILogger logger; public MyClass(ILogger<MyClass> logger) { this.logger = logger; } public void MyMethod() { // to optimize the performances, test if the log level is enabled if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug("Debug"); logger.LogTrace("Trace"); logger.LogInformation("Info"); logger.LogWarning("Warn"); logger.LogError("Error"); logger.LogCritical("Fatal"); } } |
appsettings.json |
{ "Logging": { "LogLevel": { "Default": "Information", // log level par défaut "Microsoft": "Warning", // pour les loggers commençant par Microsoft "MyNamespace.MyClass": "Debug" // pour les loggers de MyClass } } |
Program.cs |
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => { logging.ClearProviders(); // remove all the providers: no more logs }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); |
The Log methods are synchronous. There is no file log provider. |
Built-in logging providers
Console |
|
Debug | Debug window when debugging in Visual Studio On Linux journal or /var/log/message or /var/log/syslog |
EventSource | Event Tracing for Windows (ETW) |
EventLog | Windows Event Log |
TraceSource | System.Diagnostics.TraceSource libraries and providers () |
Azure App Service | text files in an Azure App Service app's file system and to blob storage in an Azure Storage account |
journal
mar 19 17:53:10 hostname logtest[29321]: fail: LogTest.Controllers.ItemController[0] mar 19 17:53:10 hostname logtest[29321]: Log message mar 19 17:58:27 hostname logtest[29321]: fail: Microsoft.AspNetCore.Server.Kestrel[13] mar 19 17:58:27 hostname logtest[29321]: Connection id "...", Request id "...": An unhandled exception was thrown by the application. mar 19 17:58:27 hostname logtest[29321]: System.Exception: exception message mar 19 17:58:27 hostname logtest[29321]: at LogTest.Controllers.ItemController.ThrowException() in /dev-path/LogTest/Controllers/ItemController.cs:line 41
apache log
- access.log is well filled by each query
- error.log is never filled
Unit tests
# create the unit tests project for MyService dotnet new xunit -o MyService.Tests # add a reference to the project to test cd MyService.Tests dotnet add reference ../MyService/MyService.csproj cd .. # create a solution if you don't have one yet dotnet new sln --name MySolution # add the unit tests project to the solution dotnet sln add ./MyService.Tests/MyService.Tests.csproj # run all the unit tests dotnet test # run the unit tests of a specific namespace / class dotnet test --filter Namespace.Class |
Code analysis
Code quality analysis
Those rules are enabled by default.
Here is how to enabled additional rules:
MyProject.csproj |
<PropertyGroup> <AnalysisLevel>latest-recommended</AnalysisLevel> </PropertyGroup> |
Prefer the use of editorconfig to globalconfig |
.globalconfig |
# Top level entry required to mark this as a global AnalyzerConfig file is_global = true # NOTE: No section headers for configuration entries #### .NET Coding Conventions #### # this. and Me. preferences dotnet_style_qualification_for_method = true:warning #### Diagnostic configuration #### # CA2007: Do not directly await a Task dotnet_diagnostic.CA2007.severity = none |
Code style analysis
# verify that all code is correctly formatted dotnet format --verify-no-changes # format all code dotnet format |
- Configuration files for code analysis rules
- An example of .editorconfig file with the default options
- Code-style rules IDExxxx
- Change encoding
.editorconfig |
############################### # Core EditorConfig Options # ############################### root = true # All files [*] charset = utf-8 ############################### # Analyzer configuration # ############################### # set the rules severity to warning dotnet_analyzer_diagnostic.severity = warning ############################### # Code Quality configuration # ############################### [*.cs] # CA1826: Use property instead of Linq Enumerable method # Exclude FirstOrDefault and LastOrDefault methods dotnet_code_quality.CA1826.exclude_ordefault_methods = true ############################### # Style configuration # ############################### # IDE0003 / IDE0009: this and Me preferences dotnet_style_qualification_for_field = true # IDE0007 / IDE0008: 'var' preferences csharp_style_var_for_built_in_types = true csharp_style_var_when_type_is_apparent = true csharp_style_var_elsewhere = true : silent # IDE0011: Add braces csharp_prefer_braces = when_multiline # IDE0022: Use expression body for methods csharp_style_expression_bodied_methods = when_on_single_line # IDE0160 / IDE0161: Namespace declaration preferences csharp_style_namespace_declarations = file_scoped ############################### # Disabled rules # ############################### # IDE0046: Use conditional expression for return dotnet_diagnostic.IDE0046.severity = suggestion # IDE0058: Remove unnecessary expression value dotnet_diagnostic.IDE0058.severity = none # CA1305: Specify IFormatProvider dotnet_diagnostic.CA1305.severity = none # CA1310: Specify StringComparison for correctness dotnet_diagnostic.CA1310.severity = none ############################### # Naming Conventions # ############################### # Style Definitions dotnet_naming_style.upper_case_style.capitalization = all_upper dotnet_naming_style.camel_case_style.capitalization = camel_case # Use UpperCase for constant fields dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_rule.constant_fields_should_be_upper_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_upper_case.style = upper_case_style dotnet_naming_rule.constant_fields_should_be_upper_case.severity = warning # Use camelCase for variables dotnet_naming_symbols.local_symbol.applicable_kinds = local dotnet_naming_rule.variables_should_be_camel_case.symbols = local_symbol dotnet_naming_rule.variables_should_be_camel_case.style = camel_case_style dotnet_naming_rule.variables_should_be_camel_case.severity = warning # Use camelCase for parameters dotnet_naming_symbols.parameter_symbol.applicable_kinds = parameter dotnet_naming_rule.parameters_should_be_camel_case.symbols = parameter_symbol dotnet_naming_rule.parameters_should_be_camel_case.style = camel_case_style dotnet_naming_rule.parameters_should_be_camel_case.severity = warning |
Visual Studio Code integration
settings.json |
"omnisharp.enableRoslynAnalyzers": true, "omnisharp.enableEditorConfigSupport": true, |
Visual Studio
Set the scope of live code analysis
- Tools → Options
- Text Editor → C# → Advanced
- Run background code analysis for: Current document
- Show compiler errors and warnings for: Open documents
Roslynator
- Install the Roslynator extension in Visual Studio Code
- Configure Roslynator on a user-wide basis
- vscode → Ctrl + Shift + P → enter roslynator → select Roslynator: Open Default Configuration File (.roslynatorconfig)
~/.local/share/JosefPihrt/Roslynator/.roslynatorconfig |
is_global = true # enable all analyzers by default and set the severity to warning roslynator_analyzers.enabled_by_default = true dotnet_analyzer_diagnostic.category-roslynator.severity = warning # enable all refactorings roslynator_refactorings.enabled = true # enable all compiler diagnostic fixes roslynator_compiler_diagnostic_fixes.enabled = true # Options roslynator_accessibility_modifiers = explicit roslynator_accessor_braces_style = single_line_when_expression_is_on_single_line roslynator_array_creation_type_style = implicit_when_type_is_obvious roslynator_arrow_token_new_line = before roslynator_binary_operator_new_line = before roslynator_blank_line_after_file_scoped_namespace_declaration = true roslynator_blank_line_between_closing_brace_and_switch_section = false roslynator_blank_line_between_single_line_accessors = false roslynator_blank_line_between_using_directives = never roslynator_block_braces_style = single_line_when_empty #roslynator_body_style = block|expression roslynator_conditional_operator_condition_parentheses_style = omit roslynator_conditional_operator_new_line = beforeroslynator_configure_await = false roslynator_doc_comment_summary_style = multi_line roslynator_empty_string_style = field roslynator_enum_flag_value_style = decimal_number roslynator_enum_has_flag_style = method roslynator_equals_token_new_line = before roslynator_infinite_loop_style = while roslynator_max_line_length = 140 roslynator_new_line_at_end_of_file = false roslynator_new_line_before_while_in_do_statement = false roslynator_null_conditional_operator_new_line = before roslynator_null_check_style = pattern_matching roslynator_object_creation_parentheses_style = omit roslynator_object_creation_type_style = implicit_when_type_is_obvious roslynator_prefix_field_identifier_with_underscore = false roslynator_suppress_unity_script_methods = true roslynator_use_anonymous_function_or_method_group = method_group roslynator_use_block_body_when_declaration_spans_over_multiple_lines = true roslynator_use_block_body_when_expression_spans_over_multiple_lines = true roslynator_use_var_instead_of_implicit_object_creation = true # Analyzers # Add blank line between single-line declarations dotnet_diagnostic.rcs0012.severity = none # Remove braces from if-else dotnet_diagnostic.rcs1004.severity = none # Use explicit type instead of 'var' (when the type is not obvious) dotnet_diagnostic.rcs1008.severity = none # Use explicit type instead of 'var' (foreach variable) dotnet_diagnostic.rcs1009.severity = none # Use explicit type instead of 'var' (when the type is obvious) dotnet_diagnostic.rcs1012.severity = none # Avoid unnecessary boxing of value type dotnet_diagnostic.rcs1198.severity = none # Mark publicly visible type with DebuggerDisplay attribute dotnet_diagnostic.rcs1223.severity = none |
Roslynator CLI
# install dotnet tool install -g roslynator.dotnet.cli roslynator analyze \ --analyzer-assemblies \ ~/.vscode/extensions/josefpihrt-vscode.roslynator-4.3.0/roslyn/common \ ~/.vscode/extensions/josefpihrt-vscode.roslynator-4.3.0/roslyn/analyzers |
To fix the error: Could not load file or assembly 'System.Composition.AttributedModel, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
|
Code coverage
# add the XunitXML.TestLogger nuget package to the unit test project dotnet add package XunitXML.TestLogger # run unit tests with Coverlet data collector and log the results dotnet test MySolution.sln --collect="XPlat Code Coverage" --logger:"xunit;LogFilePath=TestResults.xml" # creates a TestResults.xml report and a TestResults/[guid]/coverage.cobertura.xml report # extract the line coverage: xmllint --xpath "string(/coverage/@line-rate)" TestResults/[guid]/coverage.cobertura.xml sed -n -r 's/<coverage line-rate="([0-9.]+)".*/\1/p' TestResults/[guid]/coverage.cobertura.xml # install the ReportGenerator tool dotnet tool install -g dotnet-reportgenerator-globaltool # get a text summary report from all the cobertura reports reportgenerator -reports:"*/TestResults/*/coverage.cobertura.xml" -targetdir:CoverageReport -reporttypes:TextSummary # creates CoverageReport/TextSummary.txt # extract the line coverage: sed -n -r 's/Line coverage: ([0-9.]+)%/\1/p' CoverageReport/Summary.txt |
Ignore generated code
Create an .editorconfig file in a folder to not run code analysis on the files of this folder.
MyWebapi/DataAccess/.editorconfig |
[*] generated_code = true dotnet_analyzer_diagnostic.severity = silent |
ARM
# créé un dossier /bin/Debug/netcoreapp2.0/linux-arm/publish/ contenant l’exécutable et ses dépendances pour ARM dotnet publish -r linux-arm # copier le dossier linux-arm sur le serveur ARM cd linux-arm/publish ./MyApp # [1] 8952 segmentation fault (core dumped) ./MyApp # systemd-coredump[8962]: Failed to parse PID "0": Numerical result out of range # Unhandled Exception: [1] 9060 segmentation fault (core dumped) ./MyApp # systemd-coredump[9083]: Failed to parse PID "0": Numerical result out of range |
Description
Réécriture de ASP.NET:
- moderne, plus besoin de conserver la compatibilité
- léger, l'application ne charge que ce dont elle a besoin (packages MVC, Logging, Identity)
- performant
- cross platform et open source
- MVC et Web API, plus de WebForm
Migrate from ASP.NET Core 6.0 to 7.0
MyProject.csproj |
<!-- <TargetFramework>net6.0</TargetFramework> --> <TargetFramework>net7.0</TargetFramework> |
Installation
Archlinux
pacman -S aspnet-runtime dotnet-sdk # installe dotnet-host dotnet-runtime aspnet-runtime dotnet-sdk |
Ajouter ~/.dotnet/tools à PATH pour que les dotnet tools fonctionnent depuis le shell. |
Les assembly sont installées dans /usr/share/dotnet/shared/Microsoft.NETCore.App/x.y.z |
/etc/environment |
# disable .net core telemetry DOTNET_CLI_TELEMETRY_OPTOUT=1 |
Windows
- Visual Studio Installer → Workloads → ASP.NET and web development
# version de .net core installée dotnet --version |
Ubuntu ARM
Errors
Failed to bind to address http://127.0.0.1:xxxx: address already in use
lsof -i :xxxx kill -9 [PID] |