diff --git a/.gitignore b/.gitignore
index 5b59a74e..894a117e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ bld/
# vs
**/.vs/**/*
+**/**/*.csproj.user
# visual studio code
.vscode/
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 796ef925..9fc49203 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,9 +5,17 @@
+
+
+
+
+
+
+
+
-
+
@@ -28,4 +36,4 @@
-
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 31a18717..32a747db 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,7 @@ You can see them in the links below.
keep using `Dockerfile`.
- **[Reflection:](/reflection/README.md)** Researching and learning what `.Net`
offers under reflection.
+- **[Aspire:](/aspire/README.md)** Research and learn `.NET Aspire`
### ASP.NET Core
diff --git a/aspire/Aspire.AppHost/Aspire.AppHost.csproj b/aspire/Aspire.AppHost/Aspire.AppHost.csproj
new file mode 100644
index 00000000..994e0737
--- /dev/null
+++ b/aspire/Aspire.AppHost/Aspire.AppHost.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+ Exe
+ true
+ 2f4ae309-5273-4857-80b7-4968ec263b33
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aspire/Aspire.AppHost/Program.cs b/aspire/Aspire.AppHost/Program.cs
new file mode 100644
index 00000000..4cc6897f
--- /dev/null
+++ b/aspire/Aspire.AppHost/Program.cs
@@ -0,0 +1,10 @@
+var builder = DistributedApplication.CreateBuilder(args);
+
+var projectA = builder.AddProject("serviceA").WithExternalHttpEndpoints();
+
+builder.AddProject("serviceB")
+ .WithExternalHttpEndpoints()
+ .WithReference(projectA)
+ .WaitFor(projectA);
+
+builder.Build().Run();
\ No newline at end of file
diff --git a/aspire/Aspire.AppHost/Properties/launchSettings.json b/aspire/Aspire.AppHost/Properties/launchSettings.json
new file mode 100644
index 00000000..1fd5a945
--- /dev/null
+++ b/aspire/Aspire.AppHost/Properties/launchSettings.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:15046",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19115",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20062",
+ "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:17286;http://localhost:15046",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21115",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22171"
+ }
+ },
+ }
+}
diff --git a/aspire/Aspire.AppHost/appsettings.Development.json b/aspire/Aspire.AppHost/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/aspire/Aspire.AppHost/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/aspire/Aspire.AppHost/appsettings.json b/aspire/Aspire.AppHost/appsettings.json
new file mode 100644
index 00000000..31c092aa
--- /dev/null
+++ b/aspire/Aspire.AppHost/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ }
+}
diff --git a/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj b/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj
new file mode 100644
index 00000000..3b5a7358
--- /dev/null
+++ b/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj
@@ -0,0 +1,19 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aspire/Aspire.ServiceDefaults/Extensions.cs b/aspire/Aspire.ServiceDefaults/Extensions.cs
new file mode 100644
index 00000000..0a2ee48c
--- /dev/null
+++ b/aspire/Aspire.ServiceDefaults/Extensions.cs
@@ -0,0 +1,111 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+
+namespace Microsoft.Extensions.Hosting;
+
+// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
+// This project should be referenced by each service project in your solution.
+// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
+public static class Extensions
+{
+ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
+ {
+ builder.ConfigureOpenTelemetry();
+
+ builder.AddDefaultHealthChecks();
+
+ builder.Services.AddServiceDiscovery();
+
+ builder.Services.ConfigureHttpClientDefaults(http =>
+ {
+ // Turn on resilience by default
+ http.AddStandardResilienceHandler();
+
+ // Turn on service discovery by default
+ http.AddServiceDiscovery();
+ });
+
+ return builder;
+ }
+
+ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
+ {
+ builder.Logging.AddOpenTelemetry(logging =>
+ {
+ logging.IncludeFormattedMessage = true;
+ logging.IncludeScopes = true;
+ });
+
+ builder.Services.AddOpenTelemetry()
+ .WithMetrics(metrics =>
+ {
+ metrics.AddAspNetCoreInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddRuntimeInstrumentation();
+ })
+ .WithTracing(tracing =>
+ {
+ tracing.AddAspNetCoreInstrumentation()
+ // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
+ //.AddGrpcClientInstrumentation()
+ .AddHttpClientInstrumentation();
+ });
+
+ builder.AddOpenTelemetryExporters();
+
+ return builder;
+ }
+
+ private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
+ {
+ var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+
+ if (useOtlpExporter)
+ {
+ builder.Services.AddOpenTelemetry().UseOtlpExporter();
+ }
+
+ // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
+ //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
+ //{
+ // builder.Services.AddOpenTelemetry()
+ // .UseAzureMonitor();
+ //}
+
+ return builder;
+ }
+
+ public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
+ {
+ builder.Services.AddHealthChecks()
+ // Add a default liveness check to ensure app is responsive
+ .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
+
+ return builder;
+ }
+
+ public static WebApplication MapDefaultEndpoints(this WebApplication app)
+ {
+ // Adding health checks endpoints to applications in non-development environments has security implications.
+ // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
+ if (app.Environment.IsDevelopment())
+ {
+ // All health checks must pass for app to be considered ready to accept traffic after starting
+ app.MapHealthChecks("/health");
+
+ // Only health checks tagged with the "live" tag must pass for app to be considered alive
+ app.MapHealthChecks("/alive", new HealthCheckOptions
+ {
+ Predicate = r => r.Tags.Contains("live")
+ });
+ }
+
+ return app;
+ }
+}
\ No newline at end of file
diff --git a/aspire/ProjectA/Program.cs b/aspire/ProjectA/Program.cs
new file mode 100644
index 00000000..a5f9bfa3
--- /dev/null
+++ b/aspire/ProjectA/Program.cs
@@ -0,0 +1,20 @@
+var builder = WebApplication.CreateBuilder(args);
+
+builder.AddServiceDefaults();
+
+builder.Services.AddOpenApi();
+
+var app = builder.Build();
+
+if (app.Environment.IsDevelopment())
+{
+ app.MapOpenApi();
+}
+
+app.UseHttpsRedirection();
+
+app.MapGet("/", () => "Hello World! I'm ProjectA");
+
+app.MapDefaultEndpoints();
+
+app.Run();
\ No newline at end of file
diff --git a/aspire/ProjectA/ProjectA.csproj b/aspire/ProjectA/ProjectA.csproj
new file mode 100644
index 00000000..f7e22b44
--- /dev/null
+++ b/aspire/ProjectA/ProjectA.csproj
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aspire/ProjectA/Properties/launchSettings.json b/aspire/ProjectA/Properties/launchSettings.json
new file mode 100644
index 00000000..9d120b90
--- /dev/null
+++ b/aspire/ProjectA/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:5143",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:5143",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/aspire/ProjectA/appsettings.Development.json b/aspire/ProjectA/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/aspire/ProjectA/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/aspire/ProjectA/appsettings.json b/aspire/ProjectA/appsettings.json
new file mode 100644
index 00000000..10f68b8c
--- /dev/null
+++ b/aspire/ProjectA/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/aspire/ProjectB/Program.cs b/aspire/ProjectB/Program.cs
new file mode 100644
index 00000000..abc846a0
--- /dev/null
+++ b/aspire/ProjectB/Program.cs
@@ -0,0 +1,20 @@
+var builder = WebApplication.CreateBuilder(args);
+
+builder.AddServiceDefaults();
+
+builder.Services.AddOpenApi();
+
+var app = builder.Build();
+
+if (app.Environment.IsDevelopment())
+{
+ app.MapOpenApi();
+}
+
+app.UseHttpsRedirection();
+
+app.MapGet("/", () => "Hello World! I'm ProjectB");
+
+app.MapDefaultEndpoints();
+
+app.Run();
\ No newline at end of file
diff --git a/aspire/ProjectB/ProjectB.csproj b/aspire/ProjectB/ProjectB.csproj
new file mode 100644
index 00000000..f6ab5fd1
--- /dev/null
+++ b/aspire/ProjectB/ProjectB.csproj
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspire/ProjectB/Properties/launchSettings.json b/aspire/ProjectB/Properties/launchSettings.json
new file mode 100644
index 00000000..ab7a21c9
--- /dev/null
+++ b/aspire/ProjectB/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:5200",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:5200",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/aspire/ProjectB/appsettings.Development.json b/aspire/ProjectB/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/aspire/ProjectB/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/aspire/ProjectB/appsettings.json b/aspire/ProjectB/appsettings.json
new file mode 100644
index 00000000..10f68b8c
--- /dev/null
+++ b/aspire/ProjectB/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/aspire/README.md b/aspire/README.md
new file mode 100644
index 00000000..6d43c91a
--- /dev/null
+++ b/aspire/README.md
@@ -0,0 +1,132 @@
+# Aspire
+
+.NET Aspire helps manage applications, services (such as Redis), and other
+project dependencies. It also provides a dashboard for monitoring. Aspire
+consists of two main components: `AppHost` and `ServiceDefaults`.
+
+> [!WARNING]
+>
+> Only Azure supports using Aspire in cloud.
+
+> [!NOTE]
+>
+> We looked into it and found it more suitable for local testing than `docker
+> compose`, but not for production.
+
+## AppHost
+
+AppHost is the orchestration project where we manage the referenced services.
+Projects can be added as follows:
+
+[program.cs]
+```csharp
+var builder = DistributedApplication.CreateBuilder(args);
+
+var projectA = builder.AddProject("serviceA").WithExternalHttpEndpoints();
+
+builder.AddProject("serviceB")
+ .WithExternalHttpEndpoints()
+ .WithReference(projectA)
+ .WaitFor(projectA);
+
+builder.Build().Run();
+```
+
+In the example above, two service projects are added. Using extensions, we can
+configure various settings and behaviors for these projects.
+
+Once the AppHost project starts, all referenced projects will automatically
+launch, eliminating the need to start them manually.
+
+After AppHost is running, the [dashboard](#dashboard) becomes available. The
+dashboard allows us to view the added projects and monitor their details
+(telemetry, etc.), which are provided through the
+[ServiceDefaults](#servicedefault) module.
+
+## ServiceDefaults
+
+ServiceDefaults provides extensions that can be used in the added projects.
+These extensions collect project-related data, which AppHost utilizes to display
+information on the dashboard. Extension can be used as follows:
+
+[program.cs]
+```csharp
+var builder = WebApplication.CreateBuilder(args);
+
+builder.AddServiceDefaults(); // #1
+
+...
+
+var app = builder.Build();
+
+...
+
+app.MapDefaultEndpoints(); // #2
+
+app.Run();
+```
+
+## Adding or Creating Aspire
+
+To create a new Aspire project, you can use the following command:
+
+```sh
+dotnet new aspire
+```
+
+If you want to add Aspire to an existing project, modify the `.csproj` file of
+a Web API project as follows to designate it as an AppHost project:
+
+```xml
+
+
+
+ true
+ ...
+
+
+
+
+ ...
+
+
+
+```
+
+The AppHost project also requires a class library project(`ServiceDefaults`
+projects). Create a new class library and update its `.csproj` file as follows:
+
+```xml
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+If you encounter the `error ASPIRE006` SDK error while adding Aspire to an
+existing project, update the `.csproj` file to specify the correct SDK version:
+
+```xml
+
+```
+
+## Dashboard
+
+The Aspire dashboard provides a live interface for monitoring telemetry data,
+viewing logs, and starting or stopping projects in real time.
\ No newline at end of file
diff --git a/authentication/MultiAuthentication/MultiAuthentication.csproj.user b/authentication/MultiAuthentication/MultiAuthentication.csproj.user
deleted file mode 100644
index ccfffb1f..00000000
--- a/authentication/MultiAuthentication/MultiAuthentication.csproj.user
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- https
-
-
\ No newline at end of file
diff --git a/benchmarking-in-dotnet/README.md b/benchmarking-in-dotnet/README.md
index e0d8b959..f4787fb7 100644
--- a/benchmarking-in-dotnet/README.md
+++ b/benchmarking-in-dotnet/README.md
@@ -1,6 +1,6 @@
# Benchmarking in DotNet
-This is a simple project to demonstrate how we run benchmarking dotnet using
+This is a simple project to demonstrate how we run benchmarking dotnet using
[BenchmarkDotNet][] library.
## BenchmarkDotNet
@@ -12,7 +12,7 @@ This is a simple project to demonstrate how we run benchmarking dotnet using
- Add `[SimplJob]` attribute to the class
- Add `[Benchmark]` attribute to methods
-> :warning:
+> [!WARNING]
>
>`BenchmarkDotNet` library only works with console applications
@@ -28,14 +28,14 @@ See [How To Run][] for more details.
### Config
-Configs provide setup for building a benchmark by setting up various
+Configs provide setup for building a benchmark by setting up various
configuration. See [Config][] for more details.
### Jobs
Jobs define how a run is performed based. Parameters for a benchmark run
-such as _RunStrategy_,_RuntimeMoniker_,_LaunchCount_,_IterationCount_. See
-[Jobs][] for more details.
+such as _RunStrategy_,_RuntimeMoniker_,_LaunchCount_,_IterationCount_. See
+[Jobs][] for more details.
### Setup and Cleanup
@@ -44,20 +44,22 @@ invocation. See [Setup and Cleanup][] for more details
### Important Notes
-- Run benchmark tests in `RELEASE` configuration, `DEBUG` mode is not
+- Run benchmark tests in `RELEASE` configuration, `DEBUG` mode is not
recommended.
-> :bulb:
+
+> [!TIP]
>
> Enable optimize in your _.csproj_ file to run benchmarks in `DEBUG`
> configuration
> ```xml
> true
> ```
+
- Static methods are not supported, instance methods can be tested
- Benchmarked classes should have `public`
- Benchmarked methods should be `public`
- Setup and Cleanup methods does not support `Task` return type
-- We use `./.benchmark/` path for output results, add this directory to
+- We use `./.benchmark/` path for output results, add this directory to
`.gitignore` file
[BenchmarkDotNet]: https://benchmarkdotnet.org/
diff --git a/central-package-management/README.md b/central-package-management/README.md
index 01708052..91d320f0 100644
--- a/central-package-management/README.md
+++ b/central-package-management/README.md
@@ -11,7 +11,7 @@ to true so that projects can see the packages introduced here. With
Look [Directory.Packages.props](Directory.Packages.props) for example
-> :information_source:
+> [!NOTE]
>
> If you had multiple `Directory.Packages.props` files in your repository, the
> file that is closest to your project's directory will be evaluated for it and
diff --git a/dependency-injection/README.md b/dependency-injection/README.md
index 3d654167..a950937d 100644
--- a/dependency-injection/README.md
+++ b/dependency-injection/README.md
@@ -44,7 +44,7 @@ public class ServiceA(Func _newServiceB)
In this example, `ServiceA` depends on `ServiceB` explicitly, thus having a
better readability.
-> :warning:
+> [!WARNING]
>
> When registering a generic factory function, make sure you use
> `HttpContext.RequestServices` instead of root service provider. Otherwise
@@ -108,7 +108,7 @@ public void Action([FromKeyedServices("key")] ServiceType service) { }
public void Action([FromServices] ServiceType service) { }
```
-> :information_source:
+> [!NOTE]
>
> If you intentionally register more than one service with the same key, you can
> call them all using `IEnumerable` when calling the service, otherwise the last
diff --git a/dotnet-9-research-notes.md b/dotnet-9-research-notes.md
deleted file mode 100644
index 9dbe7b37..00000000
--- a/dotnet-9-research-notes.md
+++ /dev/null
@@ -1,226 +0,0 @@
-# .NET 9 Research Notes
-
-## Topics to be learn
-
-### OpenAPI
-
-#### Built-in support for OpenAPI document generation
-
-In .NET 9, ASP.NET Core provides built-in support for generating OpenAPI
-documents representing controller-based or minimal APIs via the
-`Microsoft.AspNetCore.OpenApi` package.
-
-```csharp
-var builder = WebApplication.CreateBuilder();
-
-builder.Services.AddOpenApi();
-
-var app = builder.Build();
-
-app.MapOpenApi();
-
-app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);
-
-app.Run();
-```
-
-OpenAPI documents can also be generated at build-time by adding the
-`Microsoft.Extensions.ApiDescription.Server` package.
-
-To modify the location of the emitted OpenAPI documents, set the target path in
-the `OpenApiDocumentsDirectory` property in the app's project file:
-
-```xml
-
- $(MSBuildProjectDirectory)
-
-```
-
-### Persisted assemblies
-
-`.NET 9` introduces the `PersistedAssemblyBuilder` class, which supports
-creating and saving dynamic assemblies. This brings the assembly-saving
-capabilities from `.NET Framework` to `.NET`.
-
-- **Assembly Saving**: Dynamically create types and methods, then save them as
- executable (.exe) or library (.dll) files.
-- **PDB Support**: Add symbol information for debugging.
-- **Advantage**: Simplifies migration from `.NET Framework` to `.NET 9` and
- modernizes dynamic code workflows.
-This enables assemblies to be both created and stored for later use.
-
-### Type-name parsing
-
-`TypeName` class for parsing and handling `ECMA-335` type names, similar to
-`System.Type` but independent of the runtime. It's designed for tools like
-serializers.
-
-```csharp
-using System.Reflection.Metadata;
-
-internal class RestrictedSerializationBinder
-{
- Dictionary AllowList { get; set; }
-
- RestrictedSerializationBinder(Type[] allowedTypes)
- => AllowList = allowedTypes.ToDictionary(type => type.FullName!);
-
- Type? GetType(ReadOnlySpan untrustedInput)
- {
- if (!TypeName.TryParse(untrustedInput, out TypeName? parsed))
- {
- throw new InvalidOperationException($"Invalid type name: '{untrustedInput.ToString()}'");
- }
-
- if (AllowList.TryGetValue(parsed.FullName, out Type? type))
- {
- return type;
- }
- else if (parsed.IsSimple // It's not generic, pointer, reference, or an array.
- && parsed.AssemblyName is not null
- && parsed.AssemblyName.Name == "MyTrustedAssembly"
- )
- {
- return Type.GetType(parsed.AssemblyQualifiedName, throwOnError: true);
- }
-
- throw new InvalidOperationException($"Not allowed: '{untrustedInput.ToString()}'");
- }
-}
-```
-
-## Topics to be checked for existence in the projects and updated if any
-
-### Middleware supports Keyed DI
-
-```csharp
-var builder = WebApplication.CreateBuilder(args);
-builder.Services.AddKeyedSingleton("test");
-builder.Services.AddKeyedScoped("test2");
-
-var app = builder.Build();
-app.UseMiddleware();
-app.Run();
-
-internal class MyMiddleware
-{
- private readonly RequestDelegate _next;
-
- public MyMiddleware(RequestDelegate next,
- [FromKeyedServices("test")] MySingletonClass service)
- {
- _next = next;
- }
-
- public Task Invoke(HttpContext context,
- [FromKeyedServices("test2")]
- MyScopedClass scopedService) => _next(context);
-}
-```
-
-### Linq
-
-In `Linq`, the new methods `CountBy` and `AggregateBy`, `Index` added.
-
-#### `CountBy`
-
-[Before]
-```csharp
-class User
-{
- public string Name { get; set; }
- public string Role { get; set; }
-}
-
-var users = new List
-{
- new User { Name = "Alice", Role = "Admin" },
- new User { Name = "Bob", Role = "Member" },
- new User { Name = "Charlie", Role = "Admin" },
- new User { Name = "David", Role = "Member" },
- new User { Name = "Eve", Role = "Guest" },
- new User { Name = "Frank", Role = "Admin" }
-};
-
-var roleCounts = users
- .GroupBy(user => user.Role)
- .Select(group => new { Role = group.Key, Count = group.Count() });
-```
-
-[After]
-```csharp
-var roleCounts = users.CountBy(user => user.Role);
-// [(Role, Count), (Role, Count), ....]
-```
-
-#### `AggregateBy`
-
-[Before]
-```csharp
-class User
-{
- public string Name { get; set; }
- public string Role { get; set; }
- public int AccessLevel { get; set; }
-}
-
-var users = new List
-{
- new User { Name = "Alice", Role = "Admin", AccessLevel = 10 },
- new User { Name = "Bob", Role = "Member", AccessLevel = 5 },
- new User { Name = "Charlie", Role = "Admin", AccessLevel = 20 },
- new User { Name = "David", Role = "Member", AccessLevel = 5 },
- new User { Name = "Eve", Role = "Guest", AccessLevel = 1 },
- new User { Name = "Frank", Role = "Admin", AccessLevel = 10 }
-};
-
-var accessLevelSumByRole = users
- .GroupBy(user => user.Role)
- .Select(group => new { Role = group.Key, TotalAccessLevel = group.Sum(user => user.AccessLevel) });
-```
-
-[After]
-```csharp
-var accessLevelSumByRole = users.AggregateBy(
- user => user.Role,
- seed: 0,
- (currentTotal, user) => currentTotal + user.AccessLevel);
-// [(Key, Value), (Key, Value), ...]
-```
-
-#### `Index(IEnumerable)`
-
-Makes it possible to quickly extract the implicit index of an enumerable. You
-can now write code such as the following snippet to automatically index items in
-a collection.
-
-```csharp
-IEnumerable lines2 = File.ReadAllLines("output.txt");
-foreach ((int index, string line) in lines2.Index())
-{
- Console.WriteLine($"Line number: {index + 1}, Line: {line}");
-}
-```
-
-### `BinaryFormatter` Removed
-
-It is throwing exceptions, although there's still access.
-
-### New `TimeSpan.From*` Overloads
-
-[Example]
-```csharp
-TimeSpan timeSpan1 = TimeSpan.FromSeconds(value: 101.832);
-Console.WriteLine($"timeSpan1 = {timeSpan1}");
-// timeSpan1 = 00:01:41.8319999
-
-TimeSpan timeSpan2 = TimeSpan.FromSeconds(seconds: 101, milliseconds: 832);
-Console.WriteLine($"timeSpan2 = {timeSpan2}");
-```
-
-- `FromDays`
-- `FromHours`
-- `FromMinutes`
-- `FromSeconds`
-- `FromMilliseconds`
-- `FromMicroseconds`
diff --git a/exception-handling/README.md b/exception-handling/README.md
index 0a7d4bb0..ea4f607b 100644
--- a/exception-handling/README.md
+++ b/exception-handling/README.md
@@ -21,7 +21,7 @@ To use it, we register it with `AddExceptionHandler`
builder.Services.AddExceptionHandler();
```
-> :warning:
+> [!WARNING]
>
> When registering multiple exception handlers you should pay attention to the
> order. It works according to the order of insertion.
diff --git a/learn-dotnet.sln b/learn-dotnet.sln
index f45bbb07..e1cbe029 100644
--- a/learn-dotnet.sln
+++ b/learn-dotnet.sln
@@ -138,6 +138,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "reflection", "reflection",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reflection", "reflection\Reflection\Reflection.csproj", "{E0B6EFF9-41D8-4EDF-8303-5977D6637FF6}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "aspire", "aspire", "{6EAC4719-E994-426D-87BD-6BB12FF17232}"
+ ProjectSection(SolutionItems) = preProject
+ aspire\README.md = aspire\README.md
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.AppHost", "aspire\Aspire.AppHost\Aspire.AppHost.csproj", "{FF280BA1-B772-48AC-8110-065520F3B852}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.ServiceDefaults", "aspire\Aspire.ServiceDefaults\Aspire.ServiceDefaults.csproj", "{EA1FCF65-B230-4932-9164-85C2E39449BC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectA", "aspire\ProjectA\ProjectA.csproj", "{1F34FA6D-124F-42AD-BE5F-F31FF07B9E28}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectB", "aspire\ProjectB\ProjectB.csproj", "{0DCC0BF3-FDFF-4AF7-A080-6A5D9213386F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -232,6 +245,22 @@ Global
{E0B6EFF9-41D8-4EDF-8303-5977D6637FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0B6EFF9-41D8-4EDF-8303-5977D6637FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0B6EFF9-41D8-4EDF-8303-5977D6637FF6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FF280BA1-B772-48AC-8110-065520F3B852}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FF280BA1-B772-48AC-8110-065520F3B852}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FF280BA1-B772-48AC-8110-065520F3B852}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FF280BA1-B772-48AC-8110-065520F3B852}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EA1FCF65-B230-4932-9164-85C2E39449BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EA1FCF65-B230-4932-9164-85C2E39449BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EA1FCF65-B230-4932-9164-85C2E39449BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EA1FCF65-B230-4932-9164-85C2E39449BC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1F34FA6D-124F-42AD-BE5F-F31FF07B9E28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1F34FA6D-124F-42AD-BE5F-F31FF07B9E28}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1F34FA6D-124F-42AD-BE5F-F31FF07B9E28}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1F34FA6D-124F-42AD-BE5F-F31FF07B9E28}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0DCC0BF3-FDFF-4AF7-A080-6A5D9213386F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0DCC0BF3-FDFF-4AF7-A080-6A5D9213386F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0DCC0BF3-FDFF-4AF7-A080-6A5D9213386F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0DCC0BF3-FDFF-4AF7-A080-6A5D9213386F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -281,6 +310,11 @@ Global
{AD45E9C7-D739-4513-8F01-3A6826E0F4FA} = {5EFD2336-9236-4C29-9CFD-077E702D6ACD}
{5771998F-DD44-4CEA-8B37-C2E90E5014AC} = {E148C898-1BFD-4F28-8940-583CC50F90DB}
{E0B6EFF9-41D8-4EDF-8303-5977D6637FF6} = {5771998F-DD44-4CEA-8B37-C2E90E5014AC}
+ {6EAC4719-E994-426D-87BD-6BB12FF17232} = {E148C898-1BFD-4F28-8940-583CC50F90DB}
+ {FF280BA1-B772-48AC-8110-065520F3B852} = {6EAC4719-E994-426D-87BD-6BB12FF17232}
+ {EA1FCF65-B230-4932-9164-85C2E39449BC} = {6EAC4719-E994-426D-87BD-6BB12FF17232}
+ {1F34FA6D-124F-42AD-BE5F-F31FF07B9E28} = {6EAC4719-E994-426D-87BD-6BB12FF17232}
+ {0DCC0BF3-FDFF-4AF7-A080-6A5D9213386F} = {6EAC4719-E994-426D-87BD-6BB12FF17232}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ECEAECE7-49E5-4CBC-B84D-5FF82F2399FC}
diff --git a/migration-notes.md b/migration-notes.md
deleted file mode 100644
index 45d414d1..00000000
--- a/migration-notes.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Migration Notes
-
-Here we list the operations performed when upgrading projects to .Net 9
-
-> :info:
->
-> The order is not important for now.
-
-- [ ] Upgrade `dotnet` and `language` version in `csproj` or `build.props`
-- [ ] Upgrade `dotnet` version to 9 and `checkout`, `setup-dotnet` version to
- `4` in workflows
-- [ ] Upgrade libraries to new versions
-- [ ] (Optional) If `Base64` encoded information is carried in the url, use
- `Base64Url`.
-- [ ] (Optional) If you need to take parameters with an `Array` using `params`
- and then convert to `IEnumerable` type, use `IEnumerable` instead of `Array`.
-- [ ] (Optional) `GeneratedRegex` can work with properties. It can be switched
- for a better usage.
-- [ ] (Optional) See if `UseExceptionHandler(ExceptionHandlerOptions options)`
- override is available. Especially for the `StatusCodeSelector` property.
diff --git a/model-binders/ModelBinders/ModelBinders.csproj.user b/model-binders/ModelBinders/ModelBinders.csproj.user
deleted file mode 100644
index ccfffb1f..00000000
--- a/model-binders/ModelBinders/ModelBinders.csproj.user
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- https
-
-
\ No newline at end of file
diff --git a/nullable-usage/README.md b/nullable-usage/README.md
index 49c3e30f..a3da5275 100644
--- a/nullable-usage/README.md
+++ b/nullable-usage/README.md
@@ -28,7 +28,7 @@ public class PersonService(IQueryContext? queryContext)
}
```
-> :information_source:
+> [!NOTE]
>
> The DI container will resolve every dependency before initializing the object
> and an exception will be thrown for a if a component is not registered.
@@ -54,7 +54,7 @@ public class Person(IEntityContext _context)
}
```
-> :information_source:
+> [!NOTE]
>
> Because of NHibernate, entities need a _protected_ parameterless constructor
> and compiler will highlight an error stating that the value of __context_ is
diff --git a/openapi/README.md b/openapi/README.md
index 23deb35a..09a2d74c 100644
--- a/openapi/README.md
+++ b/openapi/README.md
@@ -38,7 +38,7 @@ expose the schema, we need to map the endpoints as shown below:
app.MapOpenApi();
```
-> :warning:
+> [!WARNING]
>
> It’s a good practice to do this only in developer mode. If you don’t want to
> expose the entire schema to everyone, make sure to restrict access in
@@ -120,7 +120,7 @@ app.UseSwaggerUI(options =>
});
```
-> :warning:
+> [!WARNING]
> One important thing to note here is that `UseSwaggerUI` must be called after
> `MapOpenApi`. Otherwise, Swagger UI will not work correctly.
diff --git a/primary-constructor/README.md b/primary-constructor/README.md
index f2212259..c98d5271 100644
--- a/primary-constructor/README.md
+++ b/primary-constructor/README.md
@@ -4,7 +4,7 @@ We use Primary Constructors to achieve a better representation of required
dependencies and initialization parameters and get rid of constructors with only
assignments and no logic to have a simpler code.
-> :warning:
+> [!WARNING]
>
> .NET 8 and C# 12 are required. If you are using Visual Studio and you get
> unsupported warning, make sure you get update.
@@ -28,7 +28,7 @@ constructor, field and parameter.
If the parameter is directly used as a field, place an underscore (`_`) as a
prefix, just like a field name.
-> :bulb: This is mostly the case for dependency injection.
+> [!TIP] This is mostly the case for dependency injection.
```csharp
public class SalaryBase(SalaryCalculator _calculator)
diff --git a/publish-over-dockerfile/README.md b/publish-over-dockerfile/README.md
index 6ce83f5e..78cea264 100644
--- a/publish-over-dockerfile/README.md
+++ b/publish-over-dockerfile/README.md
@@ -1,6 +1,6 @@
# Publish Over Dockerfile
-> :warning:
+> [!WARNING]
>
> Until there is a support for credentials in remote image repositories we will
> continue to use `Dockerfile`.
@@ -14,11 +14,11 @@ For example
dotnet publish --os linux --arch x64 /t:PublishContainer -c Release
```
-> :warning:
+> [!WARNING]
>
> Before you run docker compose, you need to publish image file with publish.
-> :information_source:
+> [!NOTE]
>
> `Microsoft.NET.Build.Containers` package is needed for containerize.
diff --git a/source-generator/README.md b/source-generator/README.md
index b53d9e7e..52bf147f 100644
--- a/source-generator/README.md
+++ b/source-generator/README.md
@@ -8,7 +8,7 @@ We make the code to be generated either with the service model (schema
json) presented to us or by looking under certain namespaces according to the
content of the classes there.
-> :information_source:
+> [!NOTE]
>
> The purpose of this source generator learning is to automatically create
> controllers by inspecting the classes within the target namespace in the
@@ -32,7 +32,7 @@ content of the classes there.
> WebApp Pre Build->>+WebApp Build: Go Next Stage
> ```
-> :information_source:
+> [!NOTE]
>
> It's work with target framework `netstandard2.0` and
> `Microsoft.CodeAnalysis.CSharp 4.x` library.
@@ -69,7 +69,7 @@ schema accordingly.
We use the `Newtonsoft.Json` library to serialize and deserialize the
service model schema json provided to us.
-> :information_source:
+> [!NOTE]
>
> In order for the `Newtonsoft.Json` library to work during analyze, it must be
> added as `GeneratePathProperty="true" PrivateAssets="all"/>` and dll path
diff --git a/source-generator/WebApp/WebApp.csproj.user b/source-generator/WebApp/WebApp.csproj.user
deleted file mode 100644
index ccfffb1f..00000000
--- a/source-generator/WebApp/WebApp.csproj.user
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- https
-
-
\ No newline at end of file