Links
dotnet CLI
|
dotnet --info
dotnet new
dotnet new webapi -o [project-name] --no-https
dotnet new sln --name MySolution
dotnet sln add ./MyProject/MyProject.csproj
dotnet add reference ../otherproject/otherproject.csproj
dotnet build --configuration Release
dotnet run
ASPNETCORE_URLS="http://127.0.0.1:5123" dotnet run
dotnet run --ASPNETCORE_ENVIRONMENT Development
$env:ASPNETCORE_URLS="http://127.0.0.1:5123" ; dotnet run
dotnet test
|
Nuget packages
|
dotnet add package <package_name>
dotnet add package <package_name> --version 2.0.0
dotnet list package
dotnet list package --outdated
dotnet remove package <package_name>
|
Allows you to manage the versions of Nuget packages in a single centralized file.
Directory.Build.targets
|
<Project>
<ItemGroup>
<PackageReference Update="AutoMapper" Version="10.1.1" />
|
MyProject/MyProject.csproj
|
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<PackageReference Include="AutoMapper" />
|
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;
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
var value = Configuration.GetValue<string>("Key", "default value");
var value = Configuration["Key"];
Configuration.GetConnectionString("SqlServer1")
// dotnet add package System.Data.SqlClient
var builder = new SqlConnectionStringBuilder(Configuration.GetConnectionString("SqlServer4"));
builder.Password = Configuration["DbPassword"];
var connectionString = builder.ConnectionString;
|
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": "****"
}
|
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>();
}
|
Useful in dev environment to not store password in source code.
|
cd MyProject
dotnet user-secrets init
dotnet user-secrets set "key" "secret"
dotnet user-secrets set "ConnectionStrings:SqlServer" "server=localhost;database=test;user=test;password=****"
dotnet user-secrets set "DbPassword" "****"
dotnet user-secrets list
dotnet user-secrets remove "key"
dotnet user-secrets clear
|
WebApi/Program.cs
|
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();
builder.AddUserSecrets<Program>();
Configuration = builder.Build();
|
/etc/systemd/system/kestrel-myapp.service
|
Environment=ConnectionStrings__MyApp=server\x3dlocalhost\x3bdatabase\x3dMyDb\x3buser\x3dMyUser\x3bpassword\x3dMyPwd
Environment=SqlServerVersion=10.10.5-MariaDB
|
|
dotnet MyApp MyKey="value"
|
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)
|
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>
|
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
|
RID Catalog (list): linux-arm64, linux-x64, win10-x64
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
|
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))]
protected override void OnInitialized() { }
}
|
Linux
/etc/systemd/system/kestrel-myproject.service
|
[Unit]
Description=My Project description
[Service]
WorkingDirectory=/var/www/myproject
ExecStart=/var/www/myproject/MyProject
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=myproject
User=http
Environment=DOTNET_ROOT=/usr/share/dotnet8.0.4
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
|
|
systemd-escape "<value-to-escape>"
|
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;
Assembly.GetEntryAssembly().GetName().Version;
Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
Nuget
|
dotnet nuget locals all --list
dotnet nuget locals all --clear
dotnet nuget locals global-packages --clear
dotnet add package <package_name>
dotnet add package <package_name> --version 2.0.0
dotnet list package
dotnet remove package <package_name>
|
Allows you to manage the versions of Nuget packages in a single centralized file.
Directory.Build.targets
|
<Project>
<ItemGroup>
<PackageReference Update="AutoMapper" Version="10.1.1" />
|
MyProject/MyProject.csproj
|
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<PackageReference Include="AutoMapper" />
|
Git
.gitignore
|
bin/
obj/
.vs/
|
 |
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(ILogger<MyClass> logger)
{
public void MyMethod()
{
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",
"Microsoft": "Warning",
"MyNamespace.MyClass": "Debug"
}
}
|
Program.cs
|
builder.Logging.ClearProviders();
|
 |
The Log methods are synchronous.
There is no file log provider. |
Console |
- VS code "DEBUG CONSOLE" tab
- In the console window when the app is run with dotnet run
|
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
|
appsettings.json
|
{
"Logging": {
"LogLevel": {
"Default": "Error"
}
},
"Console": {
"LogLevel": {
"Default": "Information"
},
"FormatterName": "json"
}
}
|
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
|
dotnet new xunit -o MyService.Tests
cd MyService.Tests
dotnet add reference ../MyService/MyService.csproj
cd ..
dotnet new sln --name MySolution
dotnet sln add ./MyService.Tests/MyService.Tests.csproj
dotnet test
dotnet test --filter Namespace.Class
|
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
|
is_global = true
dotnet_style_qualification_for_method = true:warning
dotnet_diagnostic.CA2007.severity = none
|
Code style analysis
|
dotnet format --verify-no-changes
dotnet format
|
.editorconfig
|
root = true
[*]
indent_style = space
insert_final_newline = true
charset = utf-8
[*.csproj]
indent_size = 2
[*.json]
indent_size = 2
[*.cs]
indent_size = 4
trim_trailing_whitespace = true
dotnet_analyzer_diagnostic.severity = warning
dotnet_diagnostic.VSSpell001.severity = suggestion
dotnet_diagnostic.VSSpell002.severity = suggestion
[*.cs]
dotnet_sort_system_directives_first = true
dotnet_code_quality.CA1826.exclude_ordefault_methods = true
dotnet_style_qualification_for_field = true
csharp_style_var_for_built_in_types = true
csharp_style_var_when_type_is_apparent = true
csharp_style_var_elsewhere = true : silent
csharp_prefer_braces = when_multiline
csharp_style_expression_bodied_methods = when_on_single_line
csharp_style_namespace_declarations = file_scoped : error
dotnet_diagnostic.IDE0046.severity = suggestion
dotnet_diagnostic.IDE0058.severity = none
dotnet_diagnostic.CA1305.severity = none
dotnet_diagnostic.CA1310.severity = none
dotnet_diagnostic.CA1304.severity = suggestion
dotnet_diagnostic.CA1311.severity = suggestion
dotnet_naming_style.upper_case_style.capitalization = all_upper
dotnet_naming_style.camel_case_style.capitalization = camel_case
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
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
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
dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods
dotnet_naming_rule.async_methods_end_in_async.style = end_in_async
dotnet_naming_rule.async_methods_end_in_async.severity = suggestion
dotnet_naming_symbols.any_async_methods.applicable_kinds = method
dotnet_naming_symbols.any_async_methods.applicable_accessibilities = *
dotnet_naming_symbols.any_async_methods.required_modifiers = async
dotnet_naming_style.end_in_async.required_prefix =
dotnet_naming_style.end_in_async.required_suffix = Async
dotnet_naming_style.end_in_async.capitalization = pascal_case
dotnet_naming_style.end_in_async.word_separator =
|
Visual Studio Code integration
settings.json
|
"omnisharp.enableRoslynAnalyzers": true,
"omnisharp.enableEditorConfigSupport": true,
|
Visual Studio
- Tools → Options
- Text Editor → C# → Advanced
- Run background code analysis for: Current document
- Show compiler errors and warnings for: Open documents
- Install the Roslynator extension in Visual Studio or 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
roslynator_analyzers.enabled_by_default = true
dotnet_analyzer_diagnostic.category-roslynator.severity = warning
roslynator_refactorings.enabled = true
roslynator_compiler_diagnostic_fixes.enabled = true
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_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
dotnet_diagnostic.rcs0012.severity = none
dotnet_diagnostic.rcs1004.severity = none
dotnet_diagnostic.rcs1008.severity = none
dotnet_diagnostic.rcs1009.severity = none
dotnet_diagnostic.rcs1012.severity = none
dotnet_diagnostic.rcs1198.severity = none
dotnet_diagnostic.rcs1223.severity = none
|
|
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'.
The system cannot find the file specified.
|
cd ~/.dotnet/tools/.store/roslynator.dotnet.cli/0.6.0/roslynator.dotnet.cli/0.6.0/tools/net7.0/any/
mv System.Composition.AttributedModel.dll System.Composition.AttributedModel-6.0.dll
cp /usr/share/dotnet/sdk/7.0.105/DotnetTools/dotnet-format/System.Composition.AttributedModel.dll .
| |
Code coverage
|
dotnet add package XunitXML.TestLogger
dotnet test MySolution.sln --collect="XPlat Code Coverage" --logger:"xunit;LogFilePath=TestResults.xml"
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
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:"*/TestResults/*/coverage.cobertura.xml" -targetdir:CoverageReport -reporttypes:TextSummary
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
|
dotnet publish -r linux-arm
cd linux-arm/publish
./MyApp
|
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
Erreur lors de la création de la vignette : /bin/bash: /usr/bin/convert: No such file or directory Error code: 127
MyProject.csproj
|
<TargetFramework>net8.0</TargetFramework>
|
Update the following nuget packages to 8.0 Microsoft.AspNetCore.* Microsoft.EntityFrameworkCore.* Microsoft.Extensions.* System.Net.Http.Json.
 |
Check your data provider (ex: Pomelo) has released a version which handles .NET 8 |
Installation
|
pacman -S 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
|
DOTNET_CLI_TELEMETRY_OPTOUT=1
|
- Visual Studio Installer → Workloads → ASP.NET and web development
|
dotnet --version
|
Errors
Failed to bind to address http://127.0.0.1:xxxx: address already in use
|
lsof -i :xxxx
kill -9 [PID]
|