diff --git a/docs/en/Community-Articles/2023-10-31-NET-8-ASP-NET-Core-Minimal-APIs/POST.md b/docs/en/Community-Articles/2023-10-31-NET-8-ASP-NET-Core-Minimal-APIs/POST.md new file mode 100644 index 0000000000..2a8f625e09 --- /dev/null +++ b/docs/en/Community-Articles/2023-10-31-NET-8-ASP-NET-Core-Minimal-APIs/POST.md @@ -0,0 +1,156 @@ +# New Minimal APIs features in ASP.NET Core 8.0 + +In this article, we will see the new features of Minimal APIs in ASP.NET Core 8.0. + +## Binding to forms + +We can bind to forms using the [FromForm] attribute. Let's see an example: + +```csharp +app.MapPost("/books", async ([FromForm] string name, + [FromForm] BookType bookType, IFormFile? cover, BookDb db) => +{ + var book = new Book + { + Name = name, + BookType = bookType + }; + + if (cover is not null) + { + var coverName = Path.GetRandomFileName(); + + using var stream = File.Create(Path.Combine("wwwroot", coverName)); + await cover.CopyToAsync(stream); + book.Cover = coverName; + } + + db.Books.Add(book); + await db.SaveChangesAsync(); + + return Results.Ok(); +}); +``` + +Another way is to use the [AsParameters] attribute, the following code binds from form values to properties of the `NewBookRequest` record struct: + +```csharp +public record NewBookRequest([FromForm] string Name, [FromForm] BookType BookType, IFormFile? Cover); + +app.MapPost("/books", async ([AsParameters] NewBookRequest request, BookDb db) => +{ + var book = new Book + { + Name = request.Name, + BookType = request.BookType + }; + + if (request.Cover is not null) + { + var coverName = Path.GetRandomFileName(); + + using var stream = File.Create(Path.Combine("wwwroot", coverName)); + await request.Cover.CopyToAsync(stream); + book.Cover = coverName; + } + + db.Books.Add(book); + await db.SaveChangesAsync(); + + return Results.Ok(); +}); +``` + +## Antiforgery + +ASP.NET Core 8.0 adds support for antiforgery tokens. We can call the `AddAntiforgery` method to register the antiforgery services and `WebApplicationBuilder` will automatically add the antiforgery middleware to the pipeline: + +```csharp +var builder = WebApplication.CreateBuilder(); + +builder.Services.AddAntiforgery(); + +var app = builder.Build(); + +// Implicitly added by WebApplicationBuilder if AddAntiforgery is called. +// app.UseAntiforgery(); + +app.MapGet("/", () => "Hello World!"); + +app.Run(); +``` + +Example of using antiforgery tokens: + +```csharp + +// Use the antiforgery service to generate tokens. +app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) => +{ + var token = antiforgery.GetAndStoreTokens(context); + return Results.Content(...., "text/html"); +}); + +// It will automatically validate the token. +app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo)); + +// Disable antiforgery validation for this endpoint. +app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo)) + .DisableAntiforgery(); +``` + + +## Native AOT + +ASP.NET Core 8.0 adds support for Native AOT. + +You can add `PublishAot` to the project file to enable Native AOT: + +```xml + + true + +``` + +### Web API (native AOT) template + +You can use the `dotnet new webapiaot` command to create a new Minimal APIs project with Native AOT enabled. + +```diff ++using System.Text.Json.Serialization; + +-var builder = WebApplication.CreateBuilder(); ++var builder = WebApplication.CreateSlimBuilder(args); + ++builder.Services.ConfigureHttpJsonOptions(options => ++{ ++ options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); ++}); + +var app = builder.Build(); + +var sampleTodos = TodoGenerator.GenerateTodos().ToArray(); + +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(); + ++[JsonSerializable(typeof(Todo[]))] ++internal partial class AppJsonSerializerContext : JsonSerializerContext ++{ ++ ++} +``` + +* Reflection isn't supported in native AOT, you must use the `JsonSerializable` attribute to specify the types that you want to serialize/deserialize. + +## References + +* https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-8.0?view=aspnetcore-8.0#minimal-apis +* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/parameter-binding?view=aspnetcore-8.0#explicit-binding-from-form-values +* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/native-aot?view=aspnetcore-8.0 \ No newline at end of file