Back to Aspnetcore

Minimal Apis6

aspnetcore/fundamentals/minimal-apis/includes/minimal-apis6.md

latest33.8 KB
Original Source

:::moniker range="= aspnetcore-6.0"

This document:

  • Provides a quick reference for Minimal APIs.
  • Is intended for experienced developers. For an introduction, see xref:tutorials/min-web-api

The Minimal APIs consist of:

WebApplication

The following code is generated by an ASP.NET Core template:

[!code-csharp]

The preceding code can be created via dotnet new web on the command line or selecting the Empty Web template in Visual Studio.

The following code creates a xref:Microsoft.AspNetCore.Builder.WebApplication (app) without explicitly creating a xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder:

[!code-csharp]

WebApplication.Create initializes a new instance of the xref:Microsoft.AspNetCore.Builder.WebApplication class with preconfigured defaults.

Working with ports

When a web app is created with Visual Studio or dotnet new, a Properties/launchSettings.json file is created that specifies the ports the app responds to. In the port setting samples that follow, running the app from Visual Studio returns an error dialog Unable to connect to web server 'AppName'. Run the following port changing samples from the command line.

The following sections set the port the app responds to.

[!code-csharp]

In the preceding code, the app responds to port 3000.

Multiple ports

In the following code, the app responds to port 3000 and 4000.

[!code-csharp]

Set the port from the command line

The following command makes the app respond to port 7777:

dotnetcli
dotnet run --urls="https://localhost:7777"

If the Kestrel endpoint is also configured in the appsettings.json file, the appsettings.json file specified URL is used. For more information, see Kestrel endpoint configuration

Read the port from environment

The following code reads the port from the environment:

[!code-csharp]

The preferred way to set the port from the environment is to use the ASPNETCORE_URLS environment variable, which is shown in the following section.

Set the ports via the ASPNETCORE_URLS environment variable

The ASPNETCORE_URLS environment variable is available to set the port:

ASPNETCORE_URLS=http://localhost:3000

ASPNETCORE_URLS supports multiple URLs:

ASPNETCORE_URLS=http://localhost:3000;https://localhost:5000

Listen on all interfaces

The following samples demonstrate listening on all interfaces

http://*:3000

[!code-csharp]

http://+:3000

[!code-csharp]

http://0.0.0.0:3000

[!code-csharp]

Listen on all interfaces using ASPNETCORE_URLS

The preceding samples can use ASPNETCORE_URLS

ASPNETCORE_URLS=http://*:3000;https://+:5000;http://0.0.0.0:5005

Specify HTTPS with development certificate

[!code-csharp]

For more information on the development certificate, see Trust the ASP.NET Core HTTPS development certificate on Windows and macOS.

Specify HTTPS using a custom certificate

The following sections show how to specify the custom certificate using the appsettings.json file and via configuration.

Specify the custom certificate with appsettings.json

[!code-json]

Specify the custom certificate via configuration

[!code-csharp]

Use the certificate APIs

[!code-csharp]

Read the environment

[!code-csharp]

For more information using the environment, see xref:fundamentals/environments?view=aspnetcore-6.0

Configuration

The following code reads from the configuration system:

[!code-csharp]

For more information, see xref:fundamentals/configuration/index?view=aspnetcore-6.0

Logging

The following code writes a message to the log on application startup:

[!code-csharp]

For more information, see xref:fundamentals/logging/index?view=aspnetcore-6.0

Access the Dependency Injection (DI) container

The following code shows how to get services from the DI container during application startup:

[!code-csharp]

For more information, see xref:fundamentals/dependency-injection?view=aspnetcore-6.0.

WebApplicationBuilder

This section contains sample code using xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder.

Change the content root, application name, and environment

The following code sets the content root, application name, and environment:

[!code-csharp]

WebApplication.CreateBuilder initializes a new instance of the xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder class with preconfigured defaults.

For more information, see xref:fundamentals/index?view=aspnetcore-6.0

Change the content root, app name, and environment by environment variables or command line

The following table shows the environment variable and command-line argument used to change the content root, app name, and environment:

featureEnvironment variableCommand-line argument
Application nameASPNETCORE_APPLICATIONNAME--applicationName
Environment nameASPNETCORE_ENVIRONMENT--environment
Content rootASPNETCORE_CONTENTROOT--contentRoot

Add configuration providers

The following sample adds the INI configuration provider:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddIniFile("appsettings.ini");

var app = builder.Build();
<!-- Duplicate sample in 50-to-60-samples doc. Once PR #23461 (Migrate to .NET 6 ) merges, remove this comment so the snippet is displayed [!code-csharp[](~/migration/50-to-60-samples/samples/Web6Samples/Program.cs?name=snippet_conf)] -->

For detailed information, see File configuration providers in xref:fundamentals/configuration/index?view=aspnetcore-6.0.

Read configuration

By default the xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder reads configuration from multiple sources, including:

  • appSettings.json and appSettings.{environment}.json
  • Environment variables
  • The command line

For a complete list of configuration sources read, see Default configuration in xref:fundamentals/configuration/index?view=aspnetcore-6.0

The following code reads HelloKey from configuration and displays the value at the / endpoint. If the configuration value is null, "Hello" is assigned to message:

[!code-csharp]

Read the environment

[!code-csharp]

Add logging providers

[!code-csharp]

Add services

[!code-csharp]

Customize the IHostBuilder

Existing extension methods on xref:Microsoft.Extensions.Hosting.IHostBuilder can be accessed using the Host property:

[!code-csharp]

Customize the IWebHostBuilder

Extension methods on xref:Microsoft.AspNetCore.Hosting.IWebHostBuilder can be accessed using the WebApplicationBuilder.WebHost property.

[!code-csharp]

Change the web root

By default, the web root is relative to the content root in the wwwroot folder. Web root is where the Static File Middleware looks for static files. Web root can be changed with WebHostOptions, the command line, or with the xref:Microsoft.AspNetCore.Hosting.HostingAbstractionsWebHostBuilderExtensions.UseWebRoot%2A method:

[!code-csharp]

Custom dependency injection (DI) container

The following example uses Autofac:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

// Register services directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory.
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule()));

var app = builder.Build();

Add Middleware

Any existing ASP.NET Core middleware can be configured on the WebApplication:

[!code-csharp]

For more information, see xref:fundamentals/middleware/index?view=aspnetcore-6.0

Developer exception page

xref:Microsoft.AspNetCore.Builder.WebApplication.CreateBuilder%2A?displayProperty=nameWithType initializes a new instance of the xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder class with preconfigured defaults. The developer exception page is enabled in the preconfigured defaults. When the following code is run in the development environment, navigating to / renders a friendly page that shows the exception.

[!code-csharp]

ASP.NET Core Middleware

The following table lists some of the middleware frequently used with Minimal APIs.

MiddlewareDescriptionAPI
AuthenticationProvides authentication support.xref:Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions.UseAuthentication%2A
AuthorizationProvides authorization support.xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A
CORSConfigures Cross-Origin Resource Sharing.xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A
Exception HandlerGlobally handles exceptions thrown by the middleware pipeline.xref:Microsoft.AspNetCore.Builder.ExceptionHandlerExtensions.UseExceptionHandler%2A
Forwarded HeadersForwards proxied headers onto the current request.xref:Microsoft.AspNetCore.Builder.ForwardedHeadersExtensions.UseForwardedHeaders%2A
HTTPS RedirectionRedirects all HTTP requests to HTTPS.xref:Microsoft.AspNetCore.Builder.HttpsPolicyBuilderExtensions.UseHttpsRedirection%2A
HTTP Strict Transport Security (HSTS)Security enhancement middleware that adds a special response header.xref:Microsoft.AspNetCore.Builder.HstsBuilderExtensions.UseHsts%2A
Request LoggingProvides support for logging HTTP requests and responses.xref:Microsoft.AspNetCore.Builder.HttpLoggingBuilderExtensions.UseHttpLogging%2A
W3C Request LoggingProvides support for logging HTTP requests and responses in the W3C format.xref:Microsoft.AspNetCore.Builder.HttpLoggingBuilderExtensions.UseW3CLogging%2A
Response CachingProvides support for caching responses.xref:Microsoft.AspNetCore.Builder.ResponseCachingExtensions.UseResponseCaching%2A
Response CompressionProvides support for compressing responses.xref:Microsoft.AspNetCore.Builder.ResponseCompressionBuilderExtensions.UseResponseCompression%2A
SessionProvides support for managing user sessions.xref:Microsoft.AspNetCore.Builder.SessionMiddlewareExtensions.UseSession%2A
Static FilesProvides support for serving static files and directory browsing.xref:Microsoft.AspNetCore.Builder.StaticFileExtensions.UseStaticFiles%2A, xref:Microsoft.AspNetCore.Builder.FileServerExtensions.UseFileServer%2A
WebSocketsEnables the WebSockets protocol.xref:Microsoft.AspNetCore.Builder.WebSocketMiddlewareExtensions.UseWebSockets%2A

Request handling

The following sections cover routing, parameter binding, and responses.

Routing

A configured WebApplication supports Map{Verb} and xref:Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.MapMethods%2A:

[!code-csharp]

Route Handlers

Route handlers are methods that execute when the route matches. Route handlers can be a function of any shape, including synchronous or asynchronous. Route handlers can be a lambda expression, a local function, an instance method or a static method.

Lambda expression

[!code-csharp]

Local function

[!code-csharp]

Instance method

[!code-csharp]

Static method

[!code-csharp]

Endpoints can be given names in order to generate URLs to the endpoint. Using a named endpoint avoids having to hard code paths in an app:

[!code-csharp]

The preceding code displays The link to the hello endpoint is /hello from the / endpoint.

NOTE: Endpoint names are case sensitive.

Endpoint names:

  • Must be globally unique.
  • Are used as the OpenAPI operation id when OpenAPI support is enabled. For more information, see OpenAPI.

Route Parameters

Route parameters can be captured as part of the route pattern definition:

[!code-csharp]

The preceding code returns The user id is 3 and book id is 7 from the URI /users/3/books/7.

The route handler can declare the parameters to capture. When a request is made a route with parameters declared to capture, the parameters are parsed and passed to the handler. This makes it easy to capture the values in a type safe way. In the preceding code, userId and bookId are both int.

In the preceding code, if either route value cannot be converted to an int, an exception is thrown. The GET request /users/hello/books/3 throws the following exception:

BadHttpRequestException: Failed to bind parameter "int userId" from "hello".

Wildcard and catch all routes

The following catch all route returns Routing to hello from the `/posts/hello' endpoint:

[!code-csharp]

Route constraints

Route constraints constrain the matching behavior of a route.

csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/todos/{id:int}", (int id) => db.Todos.Find(id));
app.MapGet("/todos/{text}", (string text) => db.Todos.Where(t => t.Text.Contains(text)));
app.MapGet("/posts/{slug:regex(^[a-z0-9_-]+$)}", (string slug) => $"Post {slug}");

app.Run();

The following table demonstrates the preceding route templates and their behavior:

Route TemplateExample Matching URI
/todos/{id:int}/todos/1
/todos/{text}/todos/something
/posts/{slug:regex(^[a-z0-9_-]+$)}/posts/mypost

For more information, see Route constraint reference in xref:fundamentals/routing.

Parameter Binding

Parameter binding is the process of converting request data into strongly typed parameters that are expressed by route handlers. A binding source determines where parameters are bound from. Binding sources can be explicit or inferred based on HTTP method and parameter type.

Supported binding sources:

  • Route values
  • Query string
  • Header
  • Body (as JSON)
  • Services provided by dependency injection
  • Custom

[!NOTE] Binding from form values is not natively supported in .NET.

The following example GET route handler uses some of these parameter binding sources:

[!code-csharp]

The following table shows the relationship between the parameters used in the preceding example and the associated binding sources.

ParameterBinding Source
idroute value
pagequery string
customHeaderheader
serviceProvided by dependency injection

The HTTP methods GET, HEAD, OPTIONS, and DELETE don't implicitly bind from body. To bind from body (as JSON) for these HTTP methods, bind explicitly with [FromBody] or read from the xref:Microsoft.AspNetCore.Http.HttpRequest.

The following example POST route handler uses a binding source of body (as JSON) for the person parameter:

[!code-csharp]

The parameters in the preceding examples are all bound from request data automatically. To demonstrate the convenience that parameter binding provides, the following example route handlers show how to read request data directly from the request:

[!code-csharp]

Explicit Parameter Binding

Attributes can be used to explicitly declare where parameters are bound from.

<!-- TODO - finish Service -->

[!code-csharp]

ParameterBinding Source
idroute value with the name id
pagequery string with the name "p"
serviceProvided by dependency injection
contentTypeheader with the name "Content-Type"

[!NOTE] Binding from form values is not natively supported in .NET.

Parameter binding with DI

Parameter binding for Minimal APIs binds parameters through dependency injection when the type is configured as a service. It's not necessary to explicitly apply the [FromServices] attribute to a parameter. In the following code, both actions return the time:

[!code-csharp]

Optional parameters

Parameters declared in route handlers are treated as required:

  • If a request matches the route, the route handler only runs if all required parameters are provided in the request.
  • Failure to provide all required parameters results in an error.

[!code-csharp]

URIresult
/products?pageNumber=33 returned
/productsBadHttpRequestException: Required parameter "int pageNumber" was not provided from query string.
/products/1HTTP 404 error, no matching route

To make pageNumber optional, define the type as optional or provide a default value:

[!code-csharp]

URIresult
/products?pageNumber=33 returned
/products1 returned
/products21 returned

The preceding nullable and default value applies to all sources:

[!code-csharp]

The preceding code calls the method with a null product if no request body is sent.

NOTE: If invalid data is provided and the parameter is nullable, the route handler is not run.

[!code-csharp]

URIresult
/products?pageNumber=33 returned
/products1 returned
/products?pageNumber=twoBadHttpRequestException: Failed to bind parameter "Nullable<int> pageNumber" from "two".
/products/twoHTTP 404 error, no matching route

See the Binding Failures section for more information.

Special types

The following types are bound without explicit attributes:

Custom Binding

There are two ways to customize parameter binding:

  1. For route, query, and header binding sources, bind custom types by adding a static TryParse method for the type.
  2. Control the binding process by implementing a BindAsync method on a type.

TryParse

TryParse has two APIs:

csharp
public static bool TryParse(string value, out T result);
public static bool TryParse(string value, IFormatProvider provider, out T result);

The following code displays Point: 12.3, 10.1 with the URI /map?Point=12.3,10.1:

[!code-csharp]

BindAsync

BindAsync has the following APIs:

csharp
public static ValueTask<T?> BindAsync(HttpContext context, ParameterInfo parameter);
public static ValueTask<T?> BindAsync(HttpContext context);

The following code displays SortBy:xyz, SortDirection:Desc, CurrentPage:99 with the URI /products?SortBy=xyz&SortDir=Desc&Page=99:

[!code-csharp]

<a name="bf"></a>

Binding failures

When binding fails, the framework logs a debug message and returns various status codes to the client depending on the failure mode.

Failure modeNullable Parameter TypeBinding SourceStatus code
{ParameterType}.TryParse returns falseyesroute/query/header400
{ParameterType}.BindAsync returns nullyescustom400
{ParameterType}.BindAsync throwsdoes not mattercustom500
Failure to deserialize JSON bodydoes not matterbody400
Wrong content type (not application/json)does not matterbody415

Binding Precedence

The rules for determining a binding source from a parameter:

  1. Explicit attribute defined on parameter (From* attributes) in the following order:
    1. Route values: [FromRoute]
    2. Query string: [FromQuery]
    3. Header: [FromHeader]
    4. Body: [FromBody]
    5. Service: [FromServices]
  2. Special types
    1. HttpContext
    2. HttpRequest (HttpContext.Request)
    3. HttpResponse (HttpContext.Response)
    4. ClaimsPrincipal (HttpContext.User)
    5. CancellationToken (HttpContext.RequestAborted)
  3. Parameter type has a valid BindAsync method.
  4. Parameter type is a string or has a valid TryParse method.
    1. If the parameter name exists in the route template. In app.Map("/todo/{id}", (int id) => {});, id is bound from the route.
    2. Bound from the query string.
  5. If the parameter type is a service provided by dependency injection, it uses that service as the source.
  6. The parameter is from the body.

Customize JSON binding

The body binding source uses xref:System.Text.Json?displayProperty=fullName for de-serialization. It is not possible to change this default, but the binding can be customized using other techniques described previously. To customize JSON serializer options, use code similar to the following:

[!code-csharp]

The preceding code:

  • Configures both the input and output default JSON options.
  • Returns the following JSON
    json
    {
      "id": 1,
      "name": "Joe Smith"
    }
    
    When posting
    json
    {
      "Id": 1,
      "Name": "Joe Smith"
    }
    

Read the request body

Read the request body directly using a xref:Microsoft.AspNetCore.Http.HttpContext or xref:Microsoft.AspNetCore.Http.HttpRequest parameter:

[!code-csharp]

The preceding code:

Responses

Route handlers support the following types of return values:

  1. IResult based - This includes Task<IResult> and ValueTask<IResult>
  2. string - This includes Task<string> and ValueTask<string>
  3. T (Any other type) - This includes Task<T> and ValueTask<T>
Return valueBehaviorContent-Type
IResultThe framework calls IResult.ExecuteAsyncDecided by the IResult implementation
stringThe framework writes the string directly to the responsetext/plain
T (Any other type)The framework will JSON serialize the responseapplication/json

Example return values

string return values

csharp
app.MapGet("/hello", () => "Hello World");

JSON return values

csharp
app.MapGet("/hello", () => new { Message = "Hello World" });

IResult return values

csharp
app.MapGet("/hello", () => Results.Ok(new { Message = "Hello World" }));

The following example uses the built-in result types to customize the response:

[!code-csharp]

JSON
csharp
app.MapGet("/hello", () => Results.Json(new { Message = "Hello World" }));
Custom Status Code
csharp
app.MapGet("/405", () => Results.StatusCode(405));
Text
csharp
app.MapGet("/text", () => Results.Text("This is some text"));
Stream

[!code-csharp]

Redirect
csharp
app.MapGet("/old-path", () => Results.Redirect("/new-path"));
File
csharp
app.MapGet("/download", () => Results.File("myfile.text"));

Built-in results

Common result helpers exist in the Microsoft.AspNetCore.Http.Results static class.

DescriptionResponse typeStatus CodeAPI
Write a JSON response with advanced optionsapplication/json200Results.Json
Write a JSON responseapplication/json200Results.Ok
Write a text responsetext/plain (default), configurable200Results.Text
Write the response as bytesapplication/octet-stream (default), configurable200Results.Bytes
Write a stream of bytes to the responseapplication/octet-stream (default), configurable200Results.Stream
Stream a file to the response for download with the content-disposition headerapplication/octet-stream (default), configurable200Results.File
Set the status code to 404, with an optional JSON responseN/A404Results.NotFound
Set the status code to 204N/A204Results.NoContent
Set the status code to 422, with an optional JSON responseN/A422Results.UnprocessableEntity
Set the status code to 400, with an optional JSON responseN/A400Results.BadRequest
Set the status code to 409, with an optional JSON responseN/A409Results.Conflict
Write a problem details JSON object to the responseN/A500 (default), configurableResults.Problem
Write a problem details JSON object to the response with validation errorsN/AN/A, configurableResults.ValidationProblem

Customizing results

Applications can control responses by implementing a custom xref:Microsoft.AspNetCore.Http.IResult type. The following code is an example of an HTML result type:

[!code-csharp]

We recommend adding an extension method to xref:Microsoft.AspNetCore.Http.IResultExtensions?displayProperty=fullName to make these custom results more discoverable.

[!code-csharp]

Authorization

Routes can be protected using authorization policies. These can be declared via the [Authorize] attribute or by using the xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization%2A method:

[!code-csharp]

The preceding code can be written with xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization%2A:

[!code-csharp]

The following sample uses policy-based authorization:

[!code-csharp]

Allow unauthenticated users to access an endpoint

The [AllowAnonymous] allows unauthenticated users to access endpoints:

[!code-csharp]

CORS

Routes can be CORS enabled using CORS policies. CORS can be declared via the [EnableCors] attribute or by using the xref:Microsoft.AspNetCore.Builder.CorsEndpointConventionBuilderExtensions.RequireCors%2A method. The following samples enable CORS:

[!code-csharp]

[!code-csharp]

For more information, see xref:security/cors?view=aspnetcore-6.0

See also

OpenAPI support in Minimal APIs

:::moniker-end