« Asp.net core 7 » : différence entre les versions
Aucun résumé des modifications |
|||
(41 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
[[Category:.NET | [[Category:ASP.NET]] | ||
= Links = | = Links = | ||
* [https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-7.0?view=aspnetcore-7.0 What's new in ASP.NET Core 7.0] | * [https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-7.0?view=aspnetcore-7.0 What's new in ASP.NET Core 7.0] | ||
Ligne 71 : | 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 103 : | 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 200 : | 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 262 : | 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 326 : | 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 373 : | 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 414 : | 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 424 : | 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 483 : | 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 493 : | 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> | </filebox> | ||
* [https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ Code quality rules CAxxxx] | * [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> | |||
== Code style analysis == | == Code style analysis == | ||
Ligne 521 : | 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 555 : | 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 581 : | 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 697 : | Ligne 768 : | ||
== Ignore generated code == | == Ignore generated code == | ||
Create | Create an {{boxx|.editorconfig}} file in a folder to not run code analysis on the files of this folder. | ||
<filebox fn='MyWebapi/DataAccess/.editorconfig'> | <filebox fn='MyWebapi/DataAccess/.editorconfig' lang='ini'> | ||
[*] | [*] | ||
generated_code = true | generated_code = true | ||
Ligne 729 : | 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 752 : | 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 6 avril 2025 à 17:28
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 |
![]() |
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 |
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 |
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 |
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]
|