« Asp.net core 6 » : différence entre les versions
(Page créée avec « Category:.NET Core = Links = * [https://docs.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-6.0?view=aspnetcore-6.0 What's new in ASP.NET Core 6.0] ») |
Aucun résumé des modifications |
||
Ligne 2 : | Ligne 2 : | ||
= Links = | = Links = | ||
* [https://docs.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-6.0?view=aspnetcore-6.0 What's new in ASP.NET Core 6.0] | * [https://docs.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-6.0?view=aspnetcore-6.0 What's new in ASP.NET Core 6.0] | ||
* [https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.0&tabs=linux Safe storage of app secrets] | |||
* [https://docs.microsoft.com/en-us/aspnet/core Doc Microsoft] | |||
* [[:Catégorie:.NET_Core|Catégorie .NET Core]] | |||
* [https://github.com/dotnet/core/blob/master/release-notes/README.md .NET Core Release Notes] | |||
= dotnet CLI = | |||
<kode lang='bash'> | |||
# 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 -o MySolution | |||
# add a project to the solution | |||
dotnet sln add ./MyProject/MyProject.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 | |||
# run all the unit tests | |||
dotnet test | |||
</kode> | |||
= [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging Log] = | |||
By default, an app is logging into {{boxx|Console}}, {{boxx|Debug}}, {{boxx|EventSource}}, {{boxx|EventLog}} (only when running on Windows). | |||
<filebox fn='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>(); | |||
}); | |||
</filebox> | |||
<kode lang='cs'> | |||
public class MyClass | |||
{ | |||
private readonly ILogger logger; | |||
public MyClass(ILogger<MyClass> logger) | |||
{ | |||
this.logger = logger; | |||
} | |||
public void MyMethod() | |||
{ | |||
logger.LogDebug("Debug"); | |||
logger.LogTrace("Trace"); | |||
logger.LogInformation("Info"); | |||
logger.LogWarning("Warn"); | |||
logger.LogError("Error"); | |||
logger.LogCritical("Fatal"); | |||
} | |||
} | |||
</kode> | |||
<filebox fn='config.json'> | |||
{ | |||
"Logging": { | |||
"LogLevel": { | |||
"Default": "Information", // log level par défaut | |||
"Microsoft": "Warning", // pour les loggers commençant par Microsoft | |||
"MyClass": "Debug" // pour les loggers commençant par MyClass | |||
} | |||
} | |||
</filebox> | |||
== [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging#built-in-logging-providers Built-in logging providers] == | |||
{| class="wikitable wtp wtmono1" | |||
|- | |||
| Console || | |||
* VS code "DEBUG CONSOLE" tab | |||
* In the console window when the app is run with {{boxx|dotnet run}} | |||
|- | |||
| Debug || Debug window when debugging in Visual Studio<br />On Linux {{boxx|journal}} or {{boxx|/var/log/message}} or {{boxx|/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 === | |||
<pre> | |||
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 | |||
</pre> | |||
=== apache log === | |||
* {{boxx|access.log}} is well filled by each query | |||
* {{boxx|error.log}} is never filled | |||
== [https://github.com/serilog/serilog-extensions-logging-file Log dans un fichier - Serilog.Extensions.Logging.File] == | |||
* [https://nblumhardt.com/2016/10/aspnet-core-file-logger/ ASP.NET Core File Logging in one line of code] | |||
Ajoute {{boxx|Serilog.RollingFile}} comme provider, tous les log seront loggués dans un fichier.<br> | |||
NuGet → {{boxx|Serilog.Extensions.Logging.File}} | |||
<filebox fn='Startup.cs'> | |||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) | |||
{ | |||
loggerFactory.AddFile(Configuration.GetSection("Logging")); | |||
loggerFactory.AddFile( | |||
"MyApplication-{Date}.log", | |||
LogLevel.Error, // default: LogLevel.Information | |||
fileSizeLimitBytes: 1024 * 1024 * 5, // MaxSize, default 1GB (1024 * 1024 * 1024) | |||
retainedFileCountLimit: 2, // MaxNbFiles, default: 32 | |||
isJson: true); // default: false | |||
</filebox> | |||
<filebox fn='config.json'> | |||
{ | |||
"Logging": { | |||
"PathFormat": "MyApplication-{Date}.log", | |||
"LogLevel": { | |||
"Default": "Error", | |||
"Microsoft": "Information" | |||
}, | |||
"FileSizeLimitBytes": 5242880, | |||
"RetainedFileCountLimit": 2, | |||
"Json": true | |||
} | |||
} | |||
</filebox> | |||
<filebox fn='MyApplication-20180501.log'> | |||
2018-05-01T14:45:26.9980829+02:00 0HLDFC5FFGHTQ:00000004 [INF] Info (859a4ace) | |||
</filebox> | |||
<filebox fn='MyApplication-20180501.log' lang=json> | |||
{ | |||
"@t": "2018-05-01T12:51:41.3576555Z", | |||
"@m": "Info", | |||
"@i": "859a4ace", | |||
"SourceContext": "MyApp.Data.MyAppRepository", | |||
"ActionId": "7e10a1a8-7ad5-4c85-9e24-eca298b66616", | |||
"ActionName": "MyApp.Controllers.ListController.Add (MyApp)", | |||
"RequestId": "0HLDFC8VQARGR:00000008", | |||
"RequestPath": "/List/Add" | |||
} | |||
</filebox> | |||
== [https://mcguirev10.com/2018/02/07/serilog-dependency-injection-easy-ip-logging.html Serilog and Dependency Injection] == | |||
{{warn | Utiliser plutôt {{boxx|Serilog.Extensions.Logging.File}} avec la DI par défaut fournit par {{boxx|Microsoft.Extensions.Logging}}}} | |||
<filebox fn='Program.cs'> | |||
static void Main(string[] args) | |||
{ | |||
Log.Logger = new LoggerConfiguration() | |||
.WriteTo.Console(outputTemplate: customTemplate) | |||
.CreateLogger(); | |||
var services = new ServiceCollection(); | |||
services.AddTransient<IMyClass, MyClass>() | |||
.AddSingleton(Log.Logger); | |||
var provider = services.BuildServiceProvider(); | |||
var myObject = provider.GetService<IMyClass>(); | |||
myObject.MyMethod(); | |||
</filebox> | |||
<filebox fn='MyClass.cs'> | |||
public class MyClass : IMyClass | |||
{ | |||
private readonly ILogger logger; | |||
public MyClass(ILogger logger) | |||
{ | |||
this.logger = logger.ForContext<MyClass>(); | |||
} | |||
public void MyMethod() | |||
{ | |||
logger.Debug("message"); | |||
</filebox> | |||
= Nuget packages = | |||
<kode lang='bash'> | |||
# 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> | |||
</kode> | |||
== [https://www.mytechramblings.com/posts/centrally-manage-nuget-versions/ Directory.Build.targets] == | |||
Allows you to manage the versions of Nuget packages in a single centralized file. | |||
<filebox fn='Directory.Build.targets' lang=xml> | |||
<!-- Directory.Build.targets file has to be at the solution root --> | |||
<Project> | |||
<ItemGroup> | |||
<PackageReference Update="AutoMapper" Version="10.1.1" /> | |||
</filebox> | |||
<filebox fn='MyProject/MyProject.csproj' lang=xml> | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||
<ItemGroup> | |||
<!-- remove the version --> | |||
<PackageReference Include="AutoMapper" /> | |||
</filebox> | |||
= [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration Configuration] = | |||
Sources des settings par défaut dans l'ordre de lecture: | |||
# {{boxx|appsettings.json}} | |||
# {{boxx|appsettings.<EnvironmentName>.json}} | |||
# {{boxx|UserSecrets}} in {{boxx|Development}} environment | |||
# Environment variables | |||
# Command-line arguments | |||
{{info | Les settings de la source suivante écrasent ceux déjà chargés.}} | |||
<filebox fn='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; | |||
</filebox> | |||
== appsettings.json == | |||
<filebox fn='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": "****" | |||
} | |||
</filebox> | |||
=== [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1#file-configuration-provider File Configuration Provider] === | |||
Useful for using a file other than {{boxx|appsettings.config}} or for Console projects. | |||
<filebox fn='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>(); | |||
} | |||
</filebox> | |||
== [https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.1&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?] | |||
Useful in dev environment to not store password in source code. | |||
<kode lang='bash'> | |||
# 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 | |||
</kode> | |||
<filebox fn='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>(); | |||
}); | |||
</filebox> | |||
<filebox fn='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(); | |||
</filebox> | |||
== [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#evcp Environment variables] == | |||
== [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#command-line Command-line] == | |||
<kode lang='bash'> | |||
dotnet MyApp MyKey="value" | |||
</kode> | |||
= [https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments Environnement] = | |||
L’environnement utilisé est contenu dans la variable environnement {{boxx|ASPNETCORE_ENVIRONMENT}} | |||
3 valeurs sont supportées par le framework: | |||
* Development | |||
* Staging | |||
* Production (valeur par défaut) | |||
<kode lang='bash'> | |||
# lancer le service avec l'environnement Development | |||
ASPNETCORE_ENVIRONMENT=Development dotnet run | |||
dotnet run --ASPNETCORE_ENVIRONMENT Development | |||
</kode> | |||
Configuration pour la ligne de commande: | |||
<filebox fn='Properties/launchSettings.json'> | |||
{ | |||
"profiles": { | |||
"my_project": { | |||
"commandName": "Project", | |||
"launchBrowser": true, | |||
"launchUrl": "api/values", | |||
"applicationUrl": "https://localhost:5001;http://localhost:5000", | |||
"environmentVariables": { | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
} | |||
} | |||
} | |||
} | |||
</filebox> | |||
Configuration pour vs code: | |||
<filebox fn='.vscode/launch.json'> | |||
"configurations": [ | |||
{ | |||
"name": ".NET Core Launch (web)", | |||
"env": { | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
} | |||
} | |||
] | |||
</filebox> | |||
Configuration pour vs:<br> | |||
VS → Projet Properties → Debug → Environment variables → ASPNETCORE_ENVIRONMENT = Development | |||
= Deployment Scripts = | |||
<filebox fn='MyProject.csproj' lang=xml> | |||
<Target Name="MyPublishScripts" AfterTargets="BeforePublish"> | |||
<Exec Command="npm install" /> | |||
<Exec Command="gulp minify" /> | |||
<Exec Command="ng build" /> | |||
</Target> | |||
</filebox> | |||
= [https://docs.microsoft.com/en-us/dotnet/core/deploying Publish] = | |||
Applications can be published in two different modes: {{boxx|self-contained}} or {{boxx|runtime-dependent}}. | |||
* {{boxx|self-contained}} includes the .NET Core runtime and libraries, and your application and its dependencies. Users of the application can run it on a machine that doesn't have the .NET Core runtime installed. | |||
* {{boxx|runtime-dependent}} includes only your application itself and its dependencies. Users of the application have to separately install the .NET Core runtime. | |||
<kode lang='bash'> | |||
# publier dans le dossier bin\Debug\netcoreapp2.0\publish | |||
dotnet publish -c Release -r linux-arm --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]/publish or bin/[configuration]/[framework]/[runtime]/publish ) | |||
# rendre l'exécutable exécutable pour tous | |||
chmod +x bin/Release/netcoreapp2.1/ubuntu.16.04-x64/publish/myproject | |||
</kode> | |||
* [https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish dotnet publish] | |||
<filebox fn='MyProject.csproj' lang=xml> | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||
<PropertyGroup> | |||
<RuntimeIdentifier>win10-x64</RuntimeIdentifier> | |||
<RuntimeIdentifier>win10-x64,ubuntu-x64,linux-x64</RuntimeIdentifier> | |||
</PropertyGroup> | |||
</filebox> | |||
{{info | Par défaut la publication se fait en mode {{boxx|runtime-dependent}}: le dossier contient seulement les dll du projet.<br /> | |||
En spécifiant le runtime la publication se fait en mode {{boxx|self-contained}}: le dossier contient toutes les dll nécessaire ainsi qu'un exécutable adapté au runtime.}} | |||
[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|ubuntu-18.04-arm64}}, {{boxx|arch-x64}}, {{boxx|win10-x64}} | |||
== Define the port on deployed application == | |||
By defaut the following urls are used: {{boxx|<nowiki>http://localhost:5000</nowiki>}} {{boxx|<nowiki>https://localhost:5001</nowiki>}} | |||
<filebox fn='appsettings.json'> | |||
{ | |||
"Kestrel": { | |||
"EndPoints": { | |||
"Http": { | |||
"Url": "http://localhost:6000" | |||
</filebox> | |||
It can also be configured in the [[Asp.net_core#Service_file|service file]]. | |||
== Linux == | |||
* [[Nginx#.Net_Core|Configurer Nginx pour .Net Core]] | |||
* [[Apache_et_ubuntu#Dotnet_core|Configurer Apache pour .Net Core]] | |||
=== [https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-apache?view=aspnetcore-3.1#create-the-service-file Service file] === | |||
<filebox fn='/etc/systemd/system/kestrel-myproject.service' lang=ini> | |||
[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 | |||
[Install] | |||
WantedBy=multi-user.target | |||
</filebox> | |||
<kode lang='bash'> | |||
# escape value as connection string | |||
systemd-escape "<value-to-escape>" | |||
</kode> | |||
= [https://edi.wang/post/2018/9/27/get-app-version-net-core Version] = | |||
<filebox fn='MyProject.csproj' lang='xml'> | |||
<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> | |||
</filebox> | |||
<kode lang='cs'> | |||
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 | |||
</kode> | |||
= Git = | |||
<filebox fn='.gitignore' lang='bash'> | |||
# Build results | |||
bin/ | |||
obj/ | |||
# .NET Core | |||
Properties/launchSettings.json | |||
# Log files | |||
*.log | |||
</filebox> | |||
= ARM = | |||
* [https://github.com/dotnet/core/blob/master/samples/RaspberryPiInstructions.md .NET Core on Raspberry Pi] | |||
* [https://archlinuxarm.org/forum/viewtopic.php?f=60&t=11990 Archlinux ARMv7] | |||
<kode lang='bash'> | |||
# 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 | |||
</kode> | |||
= 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 | |||
[[File:ASP.NET_Core.jpg|800px]] | |||
= Installation = | |||
== [https://wiki.archlinux.org/index.php/.NET_Core Archlinux] == | |||
<kode lang='bash'> | |||
pacman -S aspnet-runtime dotnet-sdk | |||
# installe dotnet-host dotnet-runtime aspnet-runtime dotnet-sdk | |||
</kode> | |||
{{info | Ajouter {{boxx|~/.dotnet/tools}} à {{boxx|PATH}} pour que les dotnet tools fonctionnent depuis le shell.}} | |||
{{info | Les assembly sont installées dans {{boxx|/usr/share/dotnet/shared/Microsoft.NETCore.App/x.y.z}}}} | |||
<filebox fn='/etc/environment' lang='bash'> | |||
# disable .net core telemetry | |||
DOTNET_CLI_TELEMETRY_OPTOUT=1 | |||
</filebox> | |||
== [https://www.microsoft.com/net/core#windowscmd Windows] == | |||
* Visual Studio Installer → Workloads → ASP.NET and web development | |||
<kode lang='powershell'> | |||
# version de .net core installée | |||
dotnet --version | |||
</kode> |
Version du 22 janvier 2022 à 21:37
Links
- What's new in ASP.NET Core 6.0
- Safe storage of app secrets
- Doc Microsoft
- Catégorie .NET Core
- .NET Core Release Notes
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 -o MySolution # add a project to the solution dotnet sln add ./MyProject/MyProject.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 # run all the unit tests dotnet test |
Log
By default, an app is logging into Console, Debug, EventSource, EventLog (only when running on Windows).
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>(); }); |
public class MyClass { private readonly ILogger logger; public MyClass(ILogger<MyClass> logger) { this.logger = logger; } public void MyMethod() { logger.LogDebug("Debug"); logger.LogTrace("Trace"); logger.LogInformation("Info"); logger.LogWarning("Warn"); logger.LogError("Error"); logger.LogCritical("Fatal"); } } |
config.json |
{ "Logging": { "LogLevel": { "Default": "Information", // log level par défaut "Microsoft": "Warning", // pour les loggers commençant par Microsoft "MyClass": "Debug" // pour les loggers commençant par MyClass } } |
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
Log dans un fichier - Serilog.Extensions.Logging.File
Ajoute Serilog.RollingFile comme provider, tous les log seront loggués dans un fichier.
NuGet → Serilog.Extensions.Logging.File
Startup.cs |
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddFile(Configuration.GetSection("Logging")); loggerFactory.AddFile( "MyApplication-{Date}.log", LogLevel.Error, // default: LogLevel.Information fileSizeLimitBytes: 1024 * 1024 * 5, // MaxSize, default 1GB (1024 * 1024 * 1024) retainedFileCountLimit: 2, // MaxNbFiles, default: 32 isJson: true); // default: false |
config.json |
{ "Logging": { "PathFormat": "MyApplication-{Date}.log", "LogLevel": { "Default": "Error", "Microsoft": "Information" }, "FileSizeLimitBytes": 5242880, "RetainedFileCountLimit": 2, "Json": true } } |
MyApplication-20180501.log |
2018-05-01T14:45:26.9980829+02:00 0HLDFC5FFGHTQ:00000004 [INF] Info (859a4ace) |
MyApplication-20180501.log |
{ "@t": "2018-05-01T12:51:41.3576555Z", "@m": "Info", "@i": "859a4ace", "SourceContext": "MyApp.Data.MyAppRepository", "ActionId": "7e10a1a8-7ad5-4c85-9e24-eca298b66616", "ActionName": "MyApp.Controllers.ListController.Add (MyApp)", "RequestId": "0HLDFC8VQARGR:00000008", "RequestPath": "/List/Add" } |
Serilog and Dependency Injection
Utiliser plutôt Serilog.Extensions.Logging.File avec la DI par défaut fournit par Microsoft.Extensions.Logging |
Program.cs |
static void Main(string[] args) { Log.Logger = new LoggerConfiguration() .WriteTo.Console(outputTemplate: customTemplate) .CreateLogger(); var services = new ServiceCollection(); services.AddTransient<IMyClass, MyClass>() .AddSingleton(Log.Logger); var provider = services.BuildServiceProvider(); var myObject = provider.GetService<IMyClass>(); myObject.MyMethod(); |
MyClass.cs |
public class MyClass : IMyClass { private readonly ILogger logger; public MyClass(ILogger logger) { this.logger = logger.ForContext<MyClass>(); } public void MyMethod() { logger.Debug("message"); |
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(); |
Environment variables
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
Applications can be published in two different modes: self-contained or runtime-dependent.
- self-contained includes the .NET Core runtime and libraries, and your application and its dependencies. Users of the application can run it on a machine that doesn't have the .NET Core runtime installed.
- runtime-dependent includes only your application itself and its dependencies. Users of the application have to separately install the .NET Core runtime.
# publier dans le dossier bin\Debug\netcoreapp2.0\publish dotnet publish -c Release -r linux-arm --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]/publish or bin/[configuration]/[framework]/[runtime]/publish ) # rendre l'exécutable exécutable pour tous chmod +x bin/Release/netcoreapp2.1/ubuntu.16.04-x64/publish/myproject |
MyProject.csproj |
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <RuntimeIdentifier>win10-x64</RuntimeIdentifier> <RuntimeIdentifier>win10-x64,ubuntu-x64,linux-x64</RuntimeIdentifier> </PropertyGroup> |
Par défaut la publication se fait en mode runtime-dependent: le dossier contient seulement les dll du projet. En spécifiant le runtime la publication se fait en mode self-contained: le dossier contient toutes les dll nécessaire ainsi qu'un exécutable adapté au runtime. |
RID Catalog (list): ubuntu-18.04-arm64, arch-x64, win10-x64
Define the port on deployed application
By defaut the following urls are used: http://localhost:5000 https://localhost:5001
appsettings.json |
{ "Kestrel": { "EndPoints": { "Http": { "Url": "http://localhost:6000" |
It can also be configured in the service file.
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 [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 |
Git
.gitignore |
# Build results bin/ obj/ # .NET Core Properties/launchSettings.json # Log files *.log |
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
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 |