Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Minimal APIs in ASP.NET Core 6+ by Miroslav Popovic [Road to INIT 2022]

Minimal APIs in ASP.NET Core 6+ by Miroslav Popovic [Road to INIT 2022]

For quite a while, ASP.NET Core MVC was the only choice when writing REST APIs with ASP.NET Core. It is still a good and valid choice, especially for more complex REST APIs. However, we now have a new way for defining web APIs, for simpler REST APIs, microservice oriented projects, and simple web apps. Minimal APIs come without the overhead and kitchen-sink approach of MVC. We'll look into the supported features, what is missing at the moment in regard to MVC, how it can be extended with libraries like Carter, and what the future brings for Minimal API in ASP.NET Core 7+.

About the speaker:
Miroslav is senior software architect for .NET and JavaScript, employed at Seavus in the position of a technical lead. He uses .NET from version 1.0. From Windows Forms, through WPF and Silverlight, all the way to ASP.NET Core. Currently, he is focused on ASP.NET Core, client-side JavaScript development and software craftsmanship. During his career, he worked on a lot of small and big projects, including a couple of local startups. He was one of the members of the development team for the Kicks platform and one of the moderators for https://javascriptkicks.com and https://dotnetkicks.com. Besides that, he is an active community member, conference speaker and one of the leaders of "BLbit Banja Luka" user group. His blog is at https://miroslavpopovic.com.

INIT conference

September 27, 2022
Tweet

More Decks by INIT conference

Other Decks in Programming

Transcript

  1. MVC AND RAZOR PAGES • MVC – ever since ASP.NET

    MVC • December 10th, 2007 – first CTP • March 13th, 2009 – first release • April 12th 2022 – Version 5.2.8 (current) • Web API – ever since ASP.NET MVC 4 • May 31st 2012 – first version • ASP.NET Core MVC • June 27th 2016 – first version – ASP.NET vNext, ASP.NET 5 • Merges MVC and Web API • ASP.NET Razor Pages • August 14th 2017 – first version with ASP.NET Core 2 All icons in this presentation are downloaded from flaticon.com
  2. var builder = WebApplication.CreateBuilder(args); // Add services to the container.

    builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection();
  3. var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild",

    "Warm", "Balmy" }; app.MapGet("/weatherforecast", () => 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()) .WithName("GetWeatherForecast") .WithOpenApi(); app.Run(); internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); }
  4. ROUTING app.MapGet("/", () => "This is a GET"); app.MapPost("/", ()

    => "This is a POST"); app.MapPut("/", () => "This is a PUT"); app.MapDelete("/", () => "This is a DELETE"); app.MapMethods( "/options-or-head", new[] { "OPTIONS", "HEAD" }, () => "This is an options or head request ");
  5. PARAMETER BINDING app.MapGet("/{id:int}", ([FromRoute] int id, [FromQuery(Name = "p")] int

    page, [FromServices] Service service, [FromHeader(Name = "Content-Type")] string contentType) => {}); • Special types: • HttpContext • HttpRequest • HttpResponse • CancellationToken – bound to HttpContext.RequestAborted • ClaimsPrincipal
  6. RESPONSES • string – HTTP 200 with body • T

    – HTTP 200 with JSON body • IResult • Results.Json(new { value = “demo” }) • Results.Text(“demo”) • Results.StatusCode(405) • Results.NotFound(), Results.NoContent(), Results.BadRequest()... • Results.Stream(stream, “application/json”) • Results.Redirect(“/somewhere-else”) • Results.File(“file.name”) • Results.Bytes(byteArray) • Results.Problem(), Results.ValidationProblem()
  7. AUTHORIZATION • Define authorization and policies: builder.Services.AddAuthorization( o => o.AddPolicy("AdminsOnly",

    b => b.RequireClaim("admin", "true"))); • Use middleware - app.UseAuthorization(); • Require authorization with or without policy: app.MapGet("/auth", [Authorize] () => "This endpoint requires authorization."); app.MapGet("/admin", [Authorize("AdminsOnly")] () => "The /admin endpoint is for admins only."); app.MapGet("/auth2", () => "This endpoint requires authorization") .RequireAuthorization(); app.MapGet("/admin2", () => "The /admin2 endpoint is for admins only.") .RequireAuthorization("AdminsOnly"); • [AllowAnonymous] or .AllowAnonimous()
  8. CORS • Define services: builder.Services.AddCors(options => { options.AddPolicy(name: AllowSpecificOrigins, builder

    => { builder.WithOrigins("http://kulendayz.com", "https://kulendayz.com"); }); options.AddDefaultPolicy(builder => ...); }); • Use middleware: app.UseCors(); • Require CORS: app.MapGet("/", () => “Default CORS policy"); app.MapGet("/cors", [EnableCors(MyAllowSpecificOrigins)] () => "This endpoint allows cross origin requests!"); app.MapGet("/cors2", () => "This endpoint allows cross origin requests!") .RequireCors(MyAllowSpecificOrigins);
  9. OPENAPI / SWAGGER • Uses Swashbuckle library by default •

    Add services: builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); • Register middlewares: app.UseSwagger(); app.UseSwaggerUI();
  10. OPENAPI / SWAGGER (CONT.) app.MapGet("/api/v1/clients/{id:long}", GetClient) .Produces<ClientModel>() .Produces(StatusCodes.Status404NotFound) .WithName("GetClient") .WithGroupName(“v1")

    .WithSummary("Get a client by id.") .WithDescription("Gets a single client by id value.") .WithTags("Clients") .WithOpenApi(operation => { operation.Parameters[0].Description = "Id of the client to retrieve."; return operation; });
  11. INTEGRATION TESTING • Microsoft.AspNetCore.Mvc.Testing • WebApplicationFactory<T> public class DemoApplication :

    WebApplicationFactory<Program> { protected override void ConfigureWebHost( IWebHostBuilder builder) { builder.ConfigureServices(services => ...); } } • Use client from application.CreateClient() var application = new DemoApplication(); var client = application.CreateClient(); var user = await client.GetFromJsonAsync<UserModel>(“/api/v1/users/1”); Assert.Equal(1, user.Id);
  12. MISSING FEATURES IN .NET 6 • No filters support –

    IAsyncActionFilter, IAsyncExceptionFilter... • No model binding support – IModelBinderProvider, IModelBinder, also no form binding like IFormFile • No built-in validation – IModelValidator • No built-in view rendering support – use Razor Pages for views • No support for JsonPatch • No support for OData • No support for ApiVersioning
  13. IENDPOINTFILTER • IRouteHandlerFilter in older previews public interface IEndpointFilter {

    ValueTask<object?> InvokeAsync( EndpointFilterInvocationContext context, EndpointFilterDelegate next); } • Similar to middlewares
  14. OTHER IMPROVEMENTS • IFormFile and IFormFileCollection • builder.Services.AddProblemDetails(); • Improved

    OpenAPI support – more functionality, self describing APIs • Improved unit testability – IResult implementation types are public (OkObjectHttpResult, ProblemHttpResult,...) • Support for Anti-Forgery?
  15. RATELIMITING MIDDLEWARE • Primitives defined in System.Threading.RateLimiting • RateLimiter, ConcurrencyLimiter,

    TokenBucketRateLimiter, FixedWindowRateLimiter, SlidingWindowRateLimiter, PartitionedRateLimiter<Tresource> • RateLimiting Middleware • Configuring policies and attaching them to endpoints • RateLimiterOptions.GlobalLimiter – runs before any endpoint policy – i.e., limit app to handle 1000 concurrent request • https://devblogs.microsoft.com/dotnet/announcing-rate-limiting-for- dotnet/
  16. MINIMAL APIS • Beginner friendly • Low-ceremony definitions • Minimal

    overhead • Microservice ready • Still not on-par with ASP.NET Core MVC, but getting there
  17. REFERENCES • https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis • Migration to ASP.NET Core in .NET

    6 by David Fowler • https://devblogs.microsoft.com/dotnet/category/aspnet/ • https://devblogs.microsoft.com/dotnet/announcing-rate-limiting-for-dotnet/ • https://khalidabuhakmeh.com/minimal-api-validation-with-fluentvalidation • https://www.hanselman.com/blog/minimal-apis-in-net-6-but-where-are-the- unit-tests • https://dev.to/this-is-learning/maybe-it-s-time-to-rethink-our-project- structure-with-net-6-2dl