From 0398d11a1662097d71a3e3ff2887f1780c6ce5cb Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 28 Feb 2025 06:57:17 -0500 Subject: [PATCH 1/2] Primary ctors --- .../includes/usermanager-signinmanager.md | 19 ++++------ .../aot/request-delegate-generator/rdg-ids.md | 4 --- .../aot/request-delegate-generator/rdg.md | 29 +++++++++++---- .../aot/samples/10.0/rdg/Program.cs | 36 +++++++++++++++++++ .../aot/samples/10.0/rdg/RDG.csproj | 10 ++++++ .../aot/samples/{ => 8.0}/rdg/Program.cs | 1 - .../aot/samples/{ => 8.0}/rdg/RDG.csproj | 0 .../fundamentals/aot/samples/Program.cs | 1 - aspnetcore/grpc/aspnetcore.md | 16 ++++++++- aspnetcore/grpc/index.md | 31 ++++++++++++++++ aspnetcore/grpc/migration.md | 16 ++++++++- .../GrpcGreeter/Services/GreeterService.cs | 1 + 12 files changed, 136 insertions(+), 28 deletions(-) create mode 100644 aspnetcore/fundamentals/aot/samples/10.0/rdg/Program.cs create mode 100644 aspnetcore/fundamentals/aot/samples/10.0/rdg/RDG.csproj rename aspnetcore/fundamentals/aot/samples/{ => 8.0}/rdg/Program.cs (99%) rename aspnetcore/fundamentals/aot/samples/{ => 8.0}/rdg/RDG.csproj (100%) diff --git a/aspnetcore/blazor/security/includes/usermanager-signinmanager.md b/aspnetcore/blazor/security/includes/usermanager-signinmanager.md index 31c5f9ebb769..ae98e1e26f2a 100644 --- a/aspnetcore/blazor/security/includes/usermanager-signinmanager.md +++ b/aspnetcore/blazor/security/includes/usermanager-signinmanager.md @@ -30,7 +30,10 @@ services.Configure(options => The following `WeatherForecastController` logs the when the `Get` method is called. > [!NOTE] -> The following example uses a [file-scoped namespace](/dotnet/csharp/language-reference/keywords/namespace), which is a C# 10 or later (.NET 6 or later) feature. +> The following example uses: +> +> * A [file-scoped namespace](/dotnet/csharp/language-reference/keywords/namespace), which is a C# 10 or later (.NET 6 or later) feature. +> * A [primary constructor](/dotnet/csharp/whats-new/tutorials/primary-constructors), which is a C# 12 or later (.NET 8 or later) feature. ```csharp using System; @@ -49,25 +52,15 @@ namespace BlazorSample.Server.Controllers; [Authorize] [ApiController] [Route("[controller]")] -public class WeatherForecastController : ControllerBase +public class WeatherForecastController(ILogger logger, + UserManager userManager) : ControllerBase { - private readonly UserManager userManager; - private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; - private readonly ILogger logger; - - public WeatherForecastController(ILogger logger, - UserManager userManager) - { - this.logger = logger; - this.userManager = userManager; - } - [HttpGet] public async Task> Get() { diff --git a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md index 3a092aa83fad..ca1816ea8dde 100644 --- a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md +++ b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md @@ -12,12 +12,8 @@ ai-usage: ai-assisted --- # ASP.NET Core Request Delegate Generator (RDG) diagnostics - - The ASP.NET Core Request Delegate Generator (RDG) is a tool that generates request delegates for ASP.NET Core apps. The RDG is used by the native ahead-of-time (AOT) compiler to generate request delegates for the app's `Map` methods. [!INCLUDE[](~/fundamentals/aot/includes/aot_preview.md)] diff --git a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md index fef941ab05c7..d389c7739698 100644 --- a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md +++ b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md @@ -1,5 +1,4 @@ --- - title: ASP.NET Core Request Delegate Generator (RDG) for Native AOT description: Turn Map methods into request delegates with the ASP.NET Core Request Delegate Generator (RDG) for Native AOT. author: rick-anderson @@ -13,12 +12,8 @@ ai-usage: ai-assisted --- # Turn Map methods into request delegates with the ASP.NET Core Request Delegate Generator - - The ASP.NET Core Request Delegate Generator (RDG) is a compile-time source generator that compiles route handlers provided to a minimal API to request delegates that can be processed by ASP.NET Core's routing infrastructure. The RDG is implicitly enabled when applications are published with AoT enabled or when [trimming is enabled](/dotnet/core/deploying/trimming/trimming-options#enable-trimming). The RDG generates trim and native AoT-friendly code. > [!NOTE] @@ -48,7 +43,17 @@ The RDG: * Is enabled automatically in projects when publishing with Native AOT is enabled or when trimming is enabled. * Can be manually enabled even when not using Native AOT by setting `true` in the project file: -:::code language="xml" source="~/fundamentals/aot/samples/rdg/RDG.csproj" highlight="7"::: +:::moniker range=">= aspnetcore-10.0" + +:::code language="xml" source="~/fundamentals/aot/samples/10.0/rdg/RDG.csproj" highlight="7"::: + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + +:::code language="xml" source="~/fundamentals/aot/samples/8.0/rdg/RDG.csproj" highlight="7"::: + +:::moniker-end Manually enabling RDG can be useful for: @@ -57,7 +62,17 @@ Manually enabling RDG can be useful for: Minimal APIs are optimized for using , which requires using the [System.Text.Json source generator](/dotnet/standard/serialization/system-text-json/source-generation). All types accepted as parameters to or returned from request delegates in Minimal APIs must be configured on a that's registered via ASP.NET Core's dependency injection: -:::code language="csharp" source="~/fundamentals/aot/samples/rdg/Program.cs" highlight="5-9,32-99"::: +:::moniker range=">= aspnetcore-10.0" + +:::code language="csharp" source="~/fundamentals/aot/samples/10.0/rdg/Program.cs" highlight="5-9,34-36"::: + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + +:::code language="csharp" source="~/fundamentals/aot/samples/8.0/rdg/Program.cs" highlight="5-9,32-35"::: + +:::moniker-end ## Diagnostics for unsupported RDG scenarios diff --git a/aspnetcore/fundamentals/aot/samples/10.0/rdg/Program.cs b/aspnetcore/fundamentals/aot/samples/10.0/rdg/Program.cs new file mode 100644 index 000000000000..d50139281f37 --- /dev/null +++ b/aspnetcore/fundamentals/aot/samples/10.0/rdg/Program.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +var builder = WebApplication.CreateSlimBuilder(args); + +builder.Services.ConfigureHttpJsonOptions(options => +{ + options.SerializerOptions.TypeInfoResolverChain.Insert( + 0, AppJsonSerializerContext.Default); +}); + +var app = builder.Build(); + +Todo[] sampleTodos = +[ + new(1, "Walk the dog"), + new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)), + new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))), + new(4, "Clean the bathroom"), + new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2))) +]; + +var todosApi = app.MapGroup("/todos"); +todosApi.MapGet("/", () => sampleTodos); +todosApi.MapGet("/{id}", (int id) => + sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo + ? Results.Ok(todo) + : Results.NotFound()); + +app.Run(); + +public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false); + +[JsonSerializable(typeof(Todo[]))] +internal partial class AppJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/aspnetcore/fundamentals/aot/samples/10.0/rdg/RDG.csproj b/aspnetcore/fundamentals/aot/samples/10.0/rdg/RDG.csproj new file mode 100644 index 000000000000..e17c20245c91 --- /dev/null +++ b/aspnetcore/fundamentals/aot/samples/10.0/rdg/RDG.csproj @@ -0,0 +1,10 @@ + + + + net10.0 + enable + enable + true + + + diff --git a/aspnetcore/fundamentals/aot/samples/rdg/Program.cs b/aspnetcore/fundamentals/aot/samples/8.0/rdg/Program.cs similarity index 99% rename from aspnetcore/fundamentals/aot/samples/rdg/Program.cs rename to aspnetcore/fundamentals/aot/samples/8.0/rdg/Program.cs index b358c475c7b5..89a64fc42f79 100644 --- a/aspnetcore/fundamentals/aot/samples/rdg/Program.cs +++ b/aspnetcore/fundamentals/aot/samples/8.0/rdg/Program.cs @@ -32,5 +32,4 @@ public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplet [JsonSerializable(typeof(Todo[]))] internal partial class AppJsonSerializerContext : JsonSerializerContext { - } diff --git a/aspnetcore/fundamentals/aot/samples/rdg/RDG.csproj b/aspnetcore/fundamentals/aot/samples/8.0/rdg/RDG.csproj similarity index 100% rename from aspnetcore/fundamentals/aot/samples/rdg/RDG.csproj rename to aspnetcore/fundamentals/aot/samples/8.0/rdg/RDG.csproj diff --git a/aspnetcore/fundamentals/aot/samples/Program.cs b/aspnetcore/fundamentals/aot/samples/Program.cs index d71dc7e7cf18..698e706716ff 100644 --- a/aspnetcore/fundamentals/aot/samples/Program.cs +++ b/aspnetcore/fundamentals/aot/samples/Program.cs @@ -25,5 +25,4 @@ [JsonSerializable(typeof(Todo[]))] internal partial class AppJsonSerializerContext : JsonSerializerContext { - } diff --git a/aspnetcore/grpc/aspnetcore.md b/aspnetcore/grpc/aspnetcore.md index 66c9a0687ba8..fa64c06da4c1 100644 --- a/aspnetcore/grpc/aspnetcore.md +++ b/aspnetcore/grpc/aspnetcore.md @@ -153,17 +153,31 @@ For more information about using the `Microsoft.AspNetCore.App` framework refere ## Integration with ASP.NET Core APIs -gRPC services have full access to the ASP.NET Core features such as [Dependency Injection](xref:fundamentals/dependency-injection) (DI) and [Logging](xref:fundamentals/logging/index). For example, the service implementation can resolve a logger service from the DI container via the constructor: +gRPC services have full access to the ASP.NET Core features such as [dependency injection](xref:fundamentals/dependency-injection) (DI) and [logging](xref:fundamentals/logging/index). For example, the service implementation can resolve a logger service from the DI container. + +Constructor injection: ```csharp public class GreeterService : Greeter.GreeterBase { + private readonly ILogger _logger; + public GreeterService(ILogger logger) { + _logger = logger; } } ``` +Primary constructor injection (.NET 8 or later): + +```csharp +public class GreeterService(ILogger logger) : Greeter.GreeterBase +{ + ... +} +``` + By default, the gRPC service implementation can resolve other DI services with any lifetime (Singleton, Scoped, or Transient). ### Resolve HttpContext in gRPC methods diff --git a/aspnetcore/grpc/index.md b/aspnetcore/grpc/index.md index 213234e9fc37..f26f4b949ee9 100644 --- a/aspnetcore/grpc/index.md +++ b/aspnetcore/grpc/index.md @@ -14,6 +14,7 @@ uid: grpc/index By [James Newton-King](https://twitter.com/jamesnk) :::moniker range=">= aspnetcore-6.0" + [gRPC](https://grpc.io) is a language agnostic, high-performance Remote Procedure Call (RPC) framework. The main benefits of gRPC are: @@ -73,6 +74,30 @@ gRPC requires the [Grpc.AspNetCore](https://www.nuget.org/packages/Grpc.AspNetCo The **ASP.NET Core gRPC Service** project template provides a starter service: +:::moniker-end + +:::moniker range=">= aspnetcore-10.0" + +```csharp +public class GreeterService(ILogger logger) : Greeter.GreeterBase +{ + public override Task SayHello(HelloRequest request, + ServerCallContext context) + { + logger.LogInformation("Saying hello to {Name}", request.Name); + + return Task.FromResult(new HelloReply + { + Message = "Hello " + request.Name + }); + } +} +``` + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0 < aspnetcore-10.0" + ```csharp public class GreeterService : Greeter.GreeterBase { @@ -87,6 +112,7 @@ public class GreeterService : Greeter.GreeterBase ServerCallContext context) { _logger.LogInformation("Saying hello to {Name}", request.Name); + return Task.FromResult(new HelloReply { Message = "Hello " + request.Name @@ -95,6 +121,10 @@ public class GreeterService : Greeter.GreeterBase } ``` +:::moniker-end + +:::moniker range=">= aspnetcore-6.0" + `GreeterService` inherits from the `GreeterBase` type, which is generated from the `Greeter` service in the `.proto` file. The service is made accessible to clients in `Program.cs`: ```csharp @@ -132,6 +162,7 @@ For more information on creating clients, and calling different service methods, :::moniker-end :::moniker range=">= aspnetcore-3.0 < aspnetcore-6.0" + [gRPC](https://grpc.io) is a language agnostic, high-performance Remote Procedure Call (RPC) framework. The main benefits of gRPC are: diff --git a/aspnetcore/grpc/migration.md b/aspnetcore/grpc/migration.md index e0da15781c07..ce68ea96d578 100644 --- a/aspnetcore/grpc/migration.md +++ b/aspnetcore/grpc/migration.md @@ -86,17 +86,31 @@ For more information on configuration, see . ## Logging -C-core-based apps rely on the `GrpcEnvironment` to [configure the logger](https://grpc.io/grpc/csharp/api/Grpc.Core.GrpcEnvironment.html?q=size#Grpc_Core_GrpcEnvironment_SetLogger_Grpc_Core_Logging_ILogger_) for debugging purposes. The ASP.NET Core stack provides this functionality through the [Logging API](xref:fundamentals/logging/index). For example, a logger can be added to the gRPC service via constructor injection: +C-core-based apps rely on the `GrpcEnvironment` to [configure the logger](https://grpc.io/grpc/csharp/api/Grpc.Core.GrpcEnvironment.html?q=size#Grpc_Core_GrpcEnvironment_SetLogger_Grpc_Core_Logging_ILogger_) for debugging purposes. The ASP.NET Core stack provides this functionality through the [Logging API](xref:fundamentals/logging/index). For example, a logger can be added to the gRPC service. + +Constructor injection: ```csharp public class GreeterService : Greeter.GreeterBase { + private readonly ILogger _logger; + public GreeterService(ILogger logger) { + _logger = logger; } } ``` +Primary constructor injection (.NET 8 or later): + +```csharp +public class GreeterService(ILogger logger) : Greeter.GreeterBase +{ + ... +} +``` + For more information on gRPC logging and diagnostics, see . ## HTTPS diff --git a/aspnetcore/grpc/troubleshoot/sample/8.0/GrpcGreeter/Services/GreeterService.cs b/aspnetcore/grpc/troubleshoot/sample/8.0/GrpcGreeter/Services/GreeterService.cs index c091ece55a51..d07eae5ad7ae 100644 --- a/aspnetcore/grpc/troubleshoot/sample/8.0/GrpcGreeter/Services/GreeterService.cs +++ b/aspnetcore/grpc/troubleshoot/sample/8.0/GrpcGreeter/Services/GreeterService.cs @@ -6,6 +6,7 @@ namespace GrpcGreeter.Services public class GreeterService : Greeter.GreeterBase { private readonly ILogger _logger; + public GreeterService(ILogger logger) { _logger = logger; From b5a1e29ea4b25bdcd8c481683e6bdc59c62db2da Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 28 Feb 2025 07:06:48 -0500 Subject: [PATCH 2/2] Updates --- .../fundamentals/aot/request-delegate-generator/rdg-ids.md | 4 ++++ aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md index ca1816ea8dde..3a092aa83fad 100644 --- a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md +++ b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md @@ -12,8 +12,12 @@ ai-usage: ai-assisted --- # ASP.NET Core Request Delegate Generator (RDG) diagnostics + + The ASP.NET Core Request Delegate Generator (RDG) is a tool that generates request delegates for ASP.NET Core apps. The RDG is used by the native ahead-of-time (AOT) compiler to generate request delegates for the app's `Map` methods. [!INCLUDE[](~/fundamentals/aot/includes/aot_preview.md)] diff --git a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md index d389c7739698..a2c781b95ea0 100644 --- a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md +++ b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg.md @@ -12,8 +12,12 @@ ai-usage: ai-assisted --- # Turn Map methods into request delegates with the ASP.NET Core Request Delegate Generator + + The ASP.NET Core Request Delegate Generator (RDG) is a compile-time source generator that compiles route handlers provided to a minimal API to request delegates that can be processed by ASP.NET Core's routing infrastructure. The RDG is implicitly enabled when applications are published with AoT enabled or when [trimming is enabled](/dotnet/core/deploying/trimming/trimming-options#enable-trimming). The RDG generates trim and native AoT-friendly code. > [!NOTE]