From 621bd55da0326919711fb784eaedd80c29343c76 Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Wed, 29 Jan 2025 15:39:47 +0300 Subject: [PATCH 1/8] add aspire readme & update migration notes --- README.md | 1 + aspire/README.md | 1 + dotnet-9-research-notes.md | 226 ------------------------------------- migration-notes.md | 10 ++ 4 files changed, 12 insertions(+), 226 deletions(-) create mode 100644 aspire/README.md delete mode 100644 dotnet-9-research-notes.md diff --git a/README.md b/README.md index 31a1871..32a747d 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/README.md b/aspire/README.md new file mode 100644 index 0000000..1d182f0 --- /dev/null +++ b/aspire/README.md @@ -0,0 +1 @@ +# Aspire diff --git a/dotnet-9-research-notes.md b/dotnet-9-research-notes.md deleted file mode 100644 index 9dbe7b3..0000000 --- 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/migration-notes.md b/migration-notes.md index 45d414d..3967700 100644 --- a/migration-notes.md +++ b/migration-notes.md @@ -18,3 +18,13 @@ Here we list the operations performed when upgrading projects to .Net 9 for a better usage. - [ ] (Optional) See if `UseExceptionHandler(ExceptionHandlerOptions options)` override is available. Especially for the `StatusCodeSelector` property. +- [ ] (Optional) Use the new linQ extensions(`CountBy`, `AggregateBy`, + `Index(IEnumerable)`). +- [ ] (Optional) Use new `TimeSpan.From*` overloads + - `FromDays` + - `FromHours` + - `FromMinutes` + - `FromSeconds` + - `FromMilliseconds` + - `FromMicroseconds` +- [ ] (Optional) Use Keyed Services in Middlewares. From ffab3b488fc590df29f8662c44172f5ee5796798 Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Wed, 29 Jan 2025 17:22:47 +0300 Subject: [PATCH 2/8] add aspire projects --- Directory.Packages.props | 15 ++- aspire/Aspire.AppHost/Aspire.AppHost.csproj | 13 ++ aspire/Aspire.AppHost/Program.cs | 3 + .../Properties/launchSettings.json | 29 +++++ .../appsettings.Development.json | 8 ++ aspire/Aspire.AppHost/appsettings.json | 9 ++ .../Aspire.ServiceDefaults.csproj | 19 +++ aspire/Aspire.ServiceDefaults/Extensions.cs | 111 ++++++++++++++++++ aspire/ProjectA/Program.cs | 41 +++++++ aspire/ProjectA/ProjectA.csproj | 7 ++ aspire/ProjectA/ProjectA.csproj.user | 6 + .../ProjectA/Properties/launchSettings.json | 23 ++++ aspire/ProjectA/appsettings.Development.json | 8 ++ aspire/ProjectA/appsettings.json | 9 ++ aspire/ProjectB/Program.cs | 41 +++++++ aspire/ProjectB/ProjectB.csproj | 7 ++ aspire/ProjectB/ProjectB.csproj.user | 6 + .../ProjectB/Properties/launchSettings.json | 23 ++++ aspire/ProjectB/appsettings.Development.json | 8 ++ aspire/ProjectB/appsettings.json | 9 ++ aspire/README.md | 53 +++++++++ learn-dotnet.sln | 34 ++++++ openapi/OpenAPI/OpenAPI.csproj.user | 6 + 23 files changed, 483 insertions(+), 5 deletions(-) create mode 100644 aspire/Aspire.AppHost/Aspire.AppHost.csproj create mode 100644 aspire/Aspire.AppHost/Program.cs create mode 100644 aspire/Aspire.AppHost/Properties/launchSettings.json create mode 100644 aspire/Aspire.AppHost/appsettings.Development.json create mode 100644 aspire/Aspire.AppHost/appsettings.json create mode 100644 aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj create mode 100644 aspire/Aspire.ServiceDefaults/Extensions.cs create mode 100644 aspire/ProjectA/Program.cs create mode 100644 aspire/ProjectA/ProjectA.csproj create mode 100644 aspire/ProjectA/ProjectA.csproj.user create mode 100644 aspire/ProjectA/Properties/launchSettings.json create mode 100644 aspire/ProjectA/appsettings.Development.json create mode 100644 aspire/ProjectA/appsettings.json create mode 100644 aspire/ProjectB/Program.cs create mode 100644 aspire/ProjectB/ProjectB.csproj create mode 100644 aspire/ProjectB/ProjectB.csproj.user create mode 100644 aspire/ProjectB/Properties/launchSettings.json create mode 100644 aspire/ProjectB/appsettings.Development.json create mode 100644 aspire/ProjectB/appsettings.json create mode 100644 openapi/OpenAPI/OpenAPI.csproj.user diff --git a/Directory.Packages.props b/Directory.Packages.props index 796ef92..2e7510b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,13 +1,19 @@ - true - + + + + + + + + - + @@ -27,5 +33,4 @@ - - + \ No newline at end of file diff --git a/aspire/Aspire.AppHost/Aspire.AppHost.csproj b/aspire/Aspire.AppHost/Aspire.AppHost.csproj new file mode 100644 index 0000000..1566591 --- /dev/null +++ b/aspire/Aspire.AppHost/Aspire.AppHost.csproj @@ -0,0 +1,13 @@ + + + + Exe + true + 2f4ae309-5273-4857-80b7-4968ec263b33 + + + + + + + diff --git a/aspire/Aspire.AppHost/Program.cs b/aspire/Aspire.AppHost/Program.cs new file mode 100644 index 0000000..c62c3a0 --- /dev/null +++ b/aspire/Aspire.AppHost/Program.cs @@ -0,0 +1,3 @@ +var builder = DistributedApplication.CreateBuilder(args); + +builder.Build().Run(); diff --git a/aspire/Aspire.AppHost/Properties/launchSettings.json b/aspire/Aspire.AppHost/Properties/launchSettings.json new file mode 100644 index 0000000..e1c820b --- /dev/null +++ b/aspire/Aspire.AppHost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "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" + } + }, + "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" + } + } + } +} diff --git a/aspire/Aspire.AppHost/appsettings.Development.json b/aspire/Aspire.AppHost/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /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 0000000..31c092a --- /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 0000000..c567fa5 --- /dev/null +++ b/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj @@ -0,0 +1,19 @@ + + + + true + + + + + + + + + + + + + + + diff --git a/aspire/Aspire.ServiceDefaults/Extensions.cs b/aspire/Aspire.ServiceDefaults/Extensions.cs new file mode 100644 index 0000000..ce94dc2 --- /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; + } +} diff --git a/aspire/ProjectA/Program.cs b/aspire/ProjectA/Program.cs new file mode 100644 index 0000000..ee9d65d --- /dev/null +++ b/aspire/ProjectA/Program.cs @@ -0,0 +1,41 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}) +.WithName("GetWeatherForecast"); + +app.Run(); + +record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/aspire/ProjectA/ProjectA.csproj b/aspire/ProjectA/ProjectA.csproj new file mode 100644 index 0000000..d44aec3 --- /dev/null +++ b/aspire/ProjectA/ProjectA.csproj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/aspire/ProjectA/ProjectA.csproj.user b/aspire/ProjectA/ProjectA.csproj.user new file mode 100644 index 0000000..9ff5820 --- /dev/null +++ b/aspire/ProjectA/ProjectA.csproj.user @@ -0,0 +1,6 @@ + + + + https + + \ 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 0000000..2e58315 --- /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": "https://localhost:7243;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 0000000..0c208ae --- /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 0000000..10f68b8 --- /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 0000000..ee9d65d --- /dev/null +++ b/aspire/ProjectB/Program.cs @@ -0,0 +1,41 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}) +.WithName("GetWeatherForecast"); + +app.Run(); + +record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/aspire/ProjectB/ProjectB.csproj b/aspire/ProjectB/ProjectB.csproj new file mode 100644 index 0000000..d44aec3 --- /dev/null +++ b/aspire/ProjectB/ProjectB.csproj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/aspire/ProjectB/ProjectB.csproj.user b/aspire/ProjectB/ProjectB.csproj.user new file mode 100644 index 0000000..9ff5820 --- /dev/null +++ b/aspire/ProjectB/ProjectB.csproj.user @@ -0,0 +1,6 @@ + + + + https + + \ No newline at end of file diff --git a/aspire/ProjectB/Properties/launchSettings.json b/aspire/ProjectB/Properties/launchSettings.json new file mode 100644 index 0000000..92ff6cb --- /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": "https://localhost:7132;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 0000000..0c208ae --- /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 0000000..10f68b8 --- /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 index 1d182f0..155532d 100644 --- a/aspire/README.md +++ b/aspire/README.md @@ -1 +1,54 @@ # Aspire + +.Net Aspire, uygulamalarımızın, hizmetleri(redis vb) ve diğer proje bağımlılıklarını yönetmemizi sağlar. Bunları yaparken bir dashboard ile izleme imkanı sunar. Bir projeye aspire eklemek için iki projeye ihtiyacımız var. Bunlar `AppHost` ve `ServiceDefaults`'dir. + +## Add or Create Aspire + +Yeni bir proje oluşturulacaksa `dotnet new aspire` komutu ile hazır template kullanılabilir. + +Var olan projeye eklemek isteniyorsa yeni bir WebApi'nin .csproj dosyasında aşağıdaki ayarları yapmak AppHost projesi için yeterlidir + +```xml + + + + true + ... + + + + + ... + + + +``` + +AppHost projenin birde classlib projesine ihtiyacı vardır. Yeni bir classlib yaratılarak .csproj içerisinde aşağıdaki gibi düzenlemek yeterlidir. + +```xml + + + + true + + + + + + + + + + + + + + + + +``` + +## Dashboard + +Dashboard'ta projelerin ayakta olup olmamasını izlemek, logları görmek gb bir çok özelliği canlı bir şekilde izleyebileceğimiz bir arayüz sunuyor. \ No newline at end of file diff --git a/learn-dotnet.sln b/learn-dotnet.sln index f45bbb0..e1cbe02 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/openapi/OpenAPI/OpenAPI.csproj.user b/openapi/OpenAPI/OpenAPI.csproj.user new file mode 100644 index 0000000..9ff5820 --- /dev/null +++ b/openapi/OpenAPI/OpenAPI.csproj.user @@ -0,0 +1,6 @@ + + + + https + + \ No newline at end of file From f86e529261a3c89ee2b33441c99e0d7913af0cb3 Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Wed, 29 Jan 2025 19:20:03 +0300 Subject: [PATCH 3/8] learn aspire --- aspire/Aspire.AppHost/Aspire.AppHost.csproj | 7 ++ aspire/Aspire.AppHost/Program.cs | 7 ++ .../Properties/launchSettings.json | 19 ++-- aspire/ProjectA/Program.cs | 33 ++----- aspire/ProjectA/ProjectA.csproj | 4 + .../ProjectA/Properties/launchSettings.json | 2 +- aspire/ProjectB/Program.cs | 33 ++----- aspire/ProjectB/ProjectB.csproj | 4 + .../ProjectB/Properties/launchSettings.json | 2 +- aspire/README.md | 87 +++++++++++++++++-- 10 files changed, 126 insertions(+), 72 deletions(-) diff --git a/aspire/Aspire.AppHost/Aspire.AppHost.csproj b/aspire/Aspire.AppHost/Aspire.AppHost.csproj index 1566591..9ac0cf9 100644 --- a/aspire/Aspire.AppHost/Aspire.AppHost.csproj +++ b/aspire/Aspire.AppHost/Aspire.AppHost.csproj @@ -1,5 +1,7 @@ + + Exe true @@ -10,4 +12,9 @@ + + + + + diff --git a/aspire/Aspire.AppHost/Program.cs b/aspire/Aspire.AppHost/Program.cs index c62c3a0..527e732 100644 --- a/aspire/Aspire.AppHost/Program.cs +++ b/aspire/Aspire.AppHost/Program.cs @@ -1,3 +1,10 @@ var builder = DistributedApplication.CreateBuilder(args); +var projectA = builder.AddProject("serviceA").WithExternalHttpEndpoints(); + +builder.AddProject("serviceB") + .WithExternalHttpEndpoints() + .WithReference(projectA) + .WaitFor(projectA); + builder.Build().Run(); diff --git a/aspire/Aspire.AppHost/Properties/launchSettings.json b/aspire/Aspire.AppHost/Properties/launchSettings.json index e1c820b..1fd5a94 100644 --- a/aspire/Aspire.AppHost/Properties/launchSettings.json +++ b/aspire/Aspire.AppHost/Properties/launchSettings.json @@ -1,29 +1,30 @@ { "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { - "https": { + "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:17286;http://localhost:15046", + "applicationUrl": "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" + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19115", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20062", + "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true" } }, - "http": { + "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "http://localhost:15046", + "applicationUrl": "https://localhost:17286;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" + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21115", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22171" } - } + }, } } diff --git a/aspire/ProjectA/Program.cs b/aspire/ProjectA/Program.cs index ee9d65d..a5f9bfa 100644 --- a/aspire/ProjectA/Program.cs +++ b/aspire/ProjectA/Program.cs @@ -1,12 +1,11 @@ var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.AddServiceDefaults(); + builder.Services.AddOpenApi(); var app = builder.Build(); -// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); @@ -14,28 +13,8 @@ app.UseHttpsRedirection(); -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; +app.MapGet("/", () => "Hello World! I'm ProjectA"); -app.MapGet("/weatherforecast", () => -{ - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; -}) -.WithName("GetWeatherForecast"); - -app.Run(); - -record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) -{ - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); -} +app.MapDefaultEndpoints(); + +app.Run(); \ No newline at end of file diff --git a/aspire/ProjectA/ProjectA.csproj b/aspire/ProjectA/ProjectA.csproj index d44aec3..f6ab5fd 100644 --- a/aspire/ProjectA/ProjectA.csproj +++ b/aspire/ProjectA/ProjectA.csproj @@ -4,4 +4,8 @@ + + + + diff --git a/aspire/ProjectA/Properties/launchSettings.json b/aspire/ProjectA/Properties/launchSettings.json index 2e58315..9d120b9 100644 --- a/aspire/ProjectA/Properties/launchSettings.json +++ b/aspire/ProjectA/Properties/launchSettings.json @@ -14,7 +14,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "https://localhost:7243;http://localhost:5143", + "applicationUrl": "http://localhost:5143", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/aspire/ProjectB/Program.cs b/aspire/ProjectB/Program.cs index ee9d65d..abc846a 100644 --- a/aspire/ProjectB/Program.cs +++ b/aspire/ProjectB/Program.cs @@ -1,12 +1,11 @@ var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.AddServiceDefaults(); + builder.Services.AddOpenApi(); var app = builder.Build(); -// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); @@ -14,28 +13,8 @@ app.UseHttpsRedirection(); -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; +app.MapGet("/", () => "Hello World! I'm ProjectB"); -app.MapGet("/weatherforecast", () => -{ - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; -}) -.WithName("GetWeatherForecast"); - -app.Run(); - -record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) -{ - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); -} +app.MapDefaultEndpoints(); + +app.Run(); \ No newline at end of file diff --git a/aspire/ProjectB/ProjectB.csproj b/aspire/ProjectB/ProjectB.csproj index d44aec3..f6ab5fd 100644 --- a/aspire/ProjectB/ProjectB.csproj +++ b/aspire/ProjectB/ProjectB.csproj @@ -4,4 +4,8 @@ + + + + diff --git a/aspire/ProjectB/Properties/launchSettings.json b/aspire/ProjectB/Properties/launchSettings.json index 92ff6cb..ab7a21c 100644 --- a/aspire/ProjectB/Properties/launchSettings.json +++ b/aspire/ProjectB/Properties/launchSettings.json @@ -14,7 +14,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "https://localhost:7132;http://localhost:5200", + "applicationUrl": "http://localhost:5200", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/aspire/README.md b/aspire/README.md index 155532d..25c7ce3 100644 --- a/aspire/README.md +++ b/aspire/README.md @@ -1,12 +1,76 @@ # Aspire -.Net Aspire, uygulamalarımızın, hizmetleri(redis vb) ve diğer proje bağımlılıklarını yönetmemizi sağlar. Bunları yaparken bir dashboard ile izleme imkanı sunar. Bir projeye aspire eklemek için iki projeye ihtiyacımız var. Bunlar `AppHost` ve `ServiceDefaults`'dir. +.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`. -## Add or Create Aspire +> :warning: +> +> Only Azure supports using Aspire in cloud. -Yeni bir proje oluşturulacaksa `dotnet new aspire` komutu ile hazır template kullanılabilir. +## AppHost -Var olan projeye eklemek isteniyorsa yeni bir WebApi'nin .csproj dosyasında aşağıdaki ayarları yapmak AppHost projesi için yeterlidir +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 @@ -24,7 +88,8 @@ Var olan projeye eklemek isteniyorsa yeni bir WebApi'nin .csproj dosyasında aş ``` -AppHost projenin birde classlib projesine ihtiyacı vardır. Yeni bir classlib yaratılarak .csproj içerisinde aşağıdaki gibi düzenlemek yeterlidir. +The AppHost project also requires a class library project(`ServiceDefaults` +projects). Create a new class library and update its `.csproj` file as follows: ```xml @@ -36,7 +101,7 @@ AppHost projenin birde classlib projesine ihtiyacı vardır. Yeni bir classlib y - + @@ -49,6 +114,14 @@ AppHost projenin birde classlib projesine ihtiyacı vardır. Yeni bir classlib y ``` +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 -Dashboard'ta projelerin ayakta olup olmamasını izlemek, logları görmek gb bir çok özelliği canlı bir şekilde izleyebileceğimiz bir arayüz sunuyor. \ No newline at end of file +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 From ee13ca2a6e931ab30fef06ed7a8f22261d1f511b Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Wed, 29 Jan 2025 19:36:21 +0300 Subject: [PATCH 4/8] fix eol --- aspire/Aspire.AppHost/Aspire.AppHost.csproj | 2 +- aspire/ProjectA/ProjectA.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aspire/Aspire.AppHost/Aspire.AppHost.csproj b/aspire/Aspire.AppHost/Aspire.AppHost.csproj index 9ac0cf9..994e073 100644 --- a/aspire/Aspire.AppHost/Aspire.AppHost.csproj +++ b/aspire/Aspire.AppHost/Aspire.AppHost.csproj @@ -17,4 +17,4 @@ - + \ No newline at end of file diff --git a/aspire/ProjectA/ProjectA.csproj b/aspire/ProjectA/ProjectA.csproj index f6ab5fd..f7e22b4 100644 --- a/aspire/ProjectA/ProjectA.csproj +++ b/aspire/ProjectA/ProjectA.csproj @@ -8,4 +8,4 @@ - + \ No newline at end of file From 8bcf8aafa4ffc2bcf3715906c65d316bab3b66b9 Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Wed, 29 Jan 2025 20:17:10 +0300 Subject: [PATCH 5/8] fix eol --- aspire/Aspire.AppHost/Program.cs | 2 +- aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj | 2 +- aspire/Aspire.ServiceDefaults/Extensions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aspire/Aspire.AppHost/Program.cs b/aspire/Aspire.AppHost/Program.cs index 527e732..4cc6897 100644 --- a/aspire/Aspire.AppHost/Program.cs +++ b/aspire/Aspire.AppHost/Program.cs @@ -7,4 +7,4 @@ .WithReference(projectA) .WaitFor(projectA); -builder.Build().Run(); +builder.Build().Run(); \ No newline at end of file diff --git a/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj b/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj index c567fa5..3b5a735 100644 --- a/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj +++ b/aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj @@ -16,4 +16,4 @@ - + \ No newline at end of file diff --git a/aspire/Aspire.ServiceDefaults/Extensions.cs b/aspire/Aspire.ServiceDefaults/Extensions.cs index ce94dc2..0a2ee48 100644 --- a/aspire/Aspire.ServiceDefaults/Extensions.cs +++ b/aspire/Aspire.ServiceDefaults/Extensions.cs @@ -108,4 +108,4 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) return app; } -} +} \ No newline at end of file From bfa177ee723a844835503cf3747a35ea09ec4af0 Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Thu, 30 Jan 2025 19:59:31 +0300 Subject: [PATCH 6/8] update docuemnts --- .gitignore | 2 ++ aspire/README.md | 7 ++++++- benchmarking-in-dotnet/README.md | 18 ++++++++++-------- central-package-management/README.md | 2 +- dependency-injection/README.md | 4 ++-- exception-handling/README.md | 2 +- migration-notes.md | 2 +- nullable-usage/README.md | 4 ++-- openapi/README.md | 4 ++-- primary-constructor/README.md | 4 ++-- publish-over-dockerfile/README.md | 6 +++--- source-generator/README.md | 6 +++--- 12 files changed, 35 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 5b59a74..018231e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ global.json # sqlite db files **/*.sqlite + +**/**/*.csproj.user \ No newline at end of file diff --git a/aspire/README.md b/aspire/README.md index 25c7ce3..6d43c91 100644 --- a/aspire/README.md +++ b/aspire/README.md @@ -4,10 +4,15 @@ project dependencies. It also provides a dashboard for monitoring. Aspire consists of two main components: `AppHost` and `ServiceDefaults`. -> :warning: +> [!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. diff --git a/benchmarking-in-dotnet/README.md b/benchmarking-in-dotnet/README.md index e0d8b95..f4787fb 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 0170805..91d320f 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 3d65416..a950937 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/exception-handling/README.md b/exception-handling/README.md index 0a7d4bb..ea4f607 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/migration-notes.md b/migration-notes.md index 3967700..b109db9 100644 --- a/migration-notes.md +++ b/migration-notes.md @@ -2,7 +2,7 @@ Here we list the operations performed when upgrading projects to .Net 9 -> :info: +> [!NOTE] > > The order is not important for now. diff --git a/nullable-usage/README.md b/nullable-usage/README.md index 49c3e30..a3da527 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 23deb35..09a2d74 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 f221225..c98d527 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 6ce83f5..78cea26 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 b53d9e7..52bf147 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 From 7124aca467480d45ea266772bd90665cc3c675f9 Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Thu, 30 Jan 2025 20:01:04 +0300 Subject: [PATCH 7/8] remove .users file --- aspire/ProjectA/ProjectA.csproj.user | 6 ------ aspire/ProjectB/ProjectB.csproj.user | 6 ------ .../MultiAuthentication/MultiAuthentication.csproj.user | 6 ------ model-binders/ModelBinders/ModelBinders.csproj.user | 6 ------ openapi/OpenAPI/OpenAPI.csproj.user | 6 ------ source-generator/WebApp/WebApp.csproj.user | 6 ------ 6 files changed, 36 deletions(-) delete mode 100644 aspire/ProjectA/ProjectA.csproj.user delete mode 100644 aspire/ProjectB/ProjectB.csproj.user delete mode 100644 authentication/MultiAuthentication/MultiAuthentication.csproj.user delete mode 100644 model-binders/ModelBinders/ModelBinders.csproj.user delete mode 100644 openapi/OpenAPI/OpenAPI.csproj.user delete mode 100644 source-generator/WebApp/WebApp.csproj.user diff --git a/aspire/ProjectA/ProjectA.csproj.user b/aspire/ProjectA/ProjectA.csproj.user deleted file mode 100644 index 9ff5820..0000000 --- a/aspire/ProjectA/ProjectA.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - https - - \ No newline at end of file diff --git a/aspire/ProjectB/ProjectB.csproj.user b/aspire/ProjectB/ProjectB.csproj.user deleted file mode 100644 index 9ff5820..0000000 --- a/aspire/ProjectB/ProjectB.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - https - - \ 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 ccfffb1..0000000 --- a/authentication/MultiAuthentication/MultiAuthentication.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - https - - \ No newline at end of file diff --git a/model-binders/ModelBinders/ModelBinders.csproj.user b/model-binders/ModelBinders/ModelBinders.csproj.user deleted file mode 100644 index ccfffb1..0000000 --- a/model-binders/ModelBinders/ModelBinders.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - https - - \ No newline at end of file diff --git a/openapi/OpenAPI/OpenAPI.csproj.user b/openapi/OpenAPI/OpenAPI.csproj.user deleted file mode 100644 index 9ff5820..0000000 --- a/openapi/OpenAPI/OpenAPI.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - https - - \ No newline at end of file diff --git a/source-generator/WebApp/WebApp.csproj.user b/source-generator/WebApp/WebApp.csproj.user deleted file mode 100644 index ccfffb1..0000000 --- a/source-generator/WebApp/WebApp.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - https - - \ No newline at end of file From 8aae59cb1c65d72ed66cb9ed768abd31f823ae5a Mon Sep 17 00:00:00 2001 From: Sefer Mirza Date: Thu, 30 Jan 2025 20:07:14 +0300 Subject: [PATCH 8/8] fix spaces and remove migration notes --- .gitignore | 3 +-- Directory.Packages.props | 3 +++ migration-notes.md | 30 ------------------------------ 3 files changed, 4 insertions(+), 32 deletions(-) delete mode 100644 migration-notes.md diff --git a/.gitignore b/.gitignore index 018231e..894a117 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ bld/ # vs **/.vs/**/* +**/**/*.csproj.user # visual studio code .vscode/ @@ -30,5 +31,3 @@ global.json # sqlite db files **/*.sqlite - -**/**/*.csproj.user \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 2e7510b..9fc4920 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,9 @@ + true + @@ -33,4 +35,5 @@ + \ No newline at end of file diff --git a/migration-notes.md b/migration-notes.md deleted file mode 100644 index b109db9..0000000 --- a/migration-notes.md +++ /dev/null @@ -1,30 +0,0 @@ -# Migration Notes - -Here we list the operations performed when upgrading projects to .Net 9 - -> [!NOTE] -> -> 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. -- [ ] (Optional) Use the new linQ extensions(`CountBy`, `AggregateBy`, - `Index(IEnumerable)`). -- [ ] (Optional) Use new `TimeSpan.From*` overloads - - `FromDays` - - `FromHours` - - `FromMinutes` - - `FromSeconds` - - `FromMilliseconds` - - `FromMicroseconds` -- [ ] (Optional) Use Keyed Services in Middlewares.