aspnetcore/fundamentals/minimal-apis/includes/minimal-apis6.md
:::moniker range="= aspnetcore-6.0"
This document:
The Minimal APIs consist of:
WebApplicationThe following code is generated by an ASP.NET Core template:
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:
WebApplication.Create initializes a new instance of the xref:Microsoft.AspNetCore.Builder.WebApplication class with preconfigured defaults.
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.
In the preceding code, the app responds to port 3000.
In the following code, the app responds to port 3000 and 4000.
The following command makes the app respond to port 7777:
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
The following code reads the port from the environment:
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.
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
The following samples demonstrate listening on all interfaces
http://0.0.0.0:3000The preceding samples can use ASPNETCORE_URLS
ASPNETCORE_URLS=http://*:3000;https://+:5000;http://0.0.0.0:5005
For more information on the development certificate, see Trust the ASP.NET Core HTTPS development certificate on Windows and macOS.
The following sections show how to specify the custom certificate using the appsettings.json file and via configuration.
appsettings.jsonFor more information using the environment, see xref:fundamentals/environments?view=aspnetcore-6.0
The following code reads from the configuration system:
For more information, see xref:fundamentals/configuration/index?view=aspnetcore-6.0
The following code writes a message to the log on application startup:
For more information, see xref:fundamentals/logging/index?view=aspnetcore-6.0
The following code shows how to get services from the DI container during application startup:
For more information, see xref:fundamentals/dependency-injection?view=aspnetcore-6.0.
This section contains sample code using xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder.
The following code sets the content root, application name, and environment:
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
The following table shows the environment variable and command-line argument used to change the content root, app name, and environment:
| feature | Environment variable | Command-line argument |
|---|---|---|
| Application name | ASPNETCORE_APPLICATIONNAME | --applicationName |
| Environment name | ASPNETCORE_ENVIRONMENT | --environment |
| Content root | ASPNETCORE_CONTENTROOT | --contentRoot |
The following sample adds the INI configuration provider:
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddIniFile("appsettings.ini");
var app = builder.Build();
For detailed information, see File configuration providers in xref:fundamentals/configuration/index?view=aspnetcore-6.0.
By default the xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder reads configuration from multiple sources, including:
appSettings.json and appSettings.{environment}.jsonFor 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:
Existing extension methods on xref:Microsoft.Extensions.Hosting.IHostBuilder can be accessed using the Host property:
Extension methods on xref:Microsoft.AspNetCore.Hosting.IWebHostBuilder can be accessed using the WebApplicationBuilder.WebHost property.
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:
The following example uses Autofac:
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();
Any existing ASP.NET Core middleware can be configured on the WebApplication:
For more information, see xref:fundamentals/middleware/index?view=aspnetcore-6.0
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.
The following table lists some of the middleware frequently used with Minimal APIs.
The following sections cover routing, parameter binding, and responses.
A configured WebApplication supports Map{Verb} and xref:Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.MapMethods%2A:
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.
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:
The preceding code displays The link to the hello endpoint is /hello from the / endpoint.
NOTE: Endpoint names are case sensitive.
Endpoint names:
Route parameters can be captured as part of the route pattern definition:
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".
The following catch all route returns Routing to hello from the `/posts/hello' endpoint:
Route constraints constrain the matching behavior of a route.
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 Template | Example 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 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:
[!NOTE] Binding from form values is not natively supported in .NET.
The following example GET route handler uses some of these parameter binding sources:
The following table shows the relationship between the parameters used in the preceding example and the associated binding sources.
| Parameter | Binding Source |
|---|---|
id | route value |
page | query string |
customHeader | header |
service | Provided 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:
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:
Attributes can be used to explicitly declare where parameters are bound from.
<!-- TODO - finish Service -->| Parameter | Binding Source |
|---|---|
id | route value with the name id |
page | query string with the name "p" |
service | Provided by dependency injection |
contentType | header with the name "Content-Type" |
[!NOTE] Binding from form values is not natively supported in .NET.
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:
Parameters declared in route handlers are treated as required:
| URI | result |
|---|---|
/products?pageNumber=3 | 3 returned |
/products | BadHttpRequestException: Required parameter "int pageNumber" was not provided from query string. |
/products/1 | HTTP 404 error, no matching route |
To make pageNumber optional, define the type as optional or provide a default value:
| URI | result |
|---|---|
/products?pageNumber=3 | 3 returned |
/products | 1 returned |
/products2 | 1 returned |
The preceding nullable and default value applies to all sources:
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.
| URI | result |
|---|---|
/products?pageNumber=3 | 3 returned |
/products | 1 returned |
/products?pageNumber=two | BadHttpRequestException: Failed to bind parameter "Nullable<int> pageNumber" from "two". |
/products/two | HTTP 404 error, no matching route |
See the Binding Failures section for more information.
The following types are bound without explicit attributes:
xref:Microsoft.AspNetCore.Http.HttpContext: The context which holds all the information about the current HTTP request or response:
app.MapGet("/", (HttpContext context) => context.Response.WriteAsync("Hello World"));
xref:Microsoft.AspNetCore.Http.HttpRequest and xref:Microsoft.AspNetCore.Http.HttpResponse: The HTTP request and HTTP response:
app.MapGet("/", (HttpRequest request, HttpResponse response) =>
response.WriteAsync($"Hello World {request.Query["name"]}"));
xref:System.Threading.CancellationToken: The cancellation token associated with the current HTTP request:
app.MapGet("/", async (CancellationToken cancellationToken) =>
await MakeLongRunningRequestAsync(cancellationToken));
xref:System.Security.Claims.ClaimsPrincipal: The user associated with the request, bound from xref:Microsoft.AspNetCore.Http.HttpContext.User%2A?displayProperty=nameWithType:
app.MapGet("/", (ClaimsPrincipal user) => user.Identity.Name);
There are two ways to customize parameter binding:
TryParse method for the type.BindAsync method on a type.TryParse has two APIs:
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:
BindAsync has the following APIs:
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:
<a name="bf"></a>
When binding fails, the framework logs a debug message and returns various status codes to the client depending on the failure mode.
| Failure mode | Nullable Parameter Type | Binding Source | Status code |
|---|---|---|---|
{ParameterType}.TryParse returns false | yes | route/query/header | 400 |
{ParameterType}.BindAsync returns null | yes | custom | 400 |
{ParameterType}.BindAsync throws | does not matter | custom | 500 |
| Failure to deserialize JSON body | does not matter | body | 400 |
Wrong content type (not application/json) | does not matter | body | 415 |
The rules for determining a binding source from a parameter:
[FromRoute][FromQuery][FromHeader][FromBody][FromServices]BindAsync method.TryParse method.
app.Map("/todo/{id}", (int id) => {});, id is bound from the route.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:
The preceding code:
{
"id": 1,
"name": "Joe Smith"
}
{
"Id": 1,
"Name": "Joe Smith"
}
Read the request body directly using a xref:Microsoft.AspNetCore.Http.HttpContext or xref:Microsoft.AspNetCore.Http.HttpRequest parameter:
The preceding code:
Route handlers support the following types of return values:
IResult based - This includes Task<IResult> and ValueTask<IResult>string - This includes Task<string> and ValueTask<string>T (Any other type) - This includes Task<T> and ValueTask<T>| Return value | Behavior | Content-Type |
|---|---|---|
IResult | The framework calls IResult.ExecuteAsync | Decided by the IResult implementation |
string | The framework writes the string directly to the response | text/plain |
T (Any other type) | The framework will JSON serialize the response | application/json |
app.MapGet("/hello", () => "Hello World");
app.MapGet("/hello", () => new { Message = "Hello World" });
app.MapGet("/hello", () => Results.Ok(new { Message = "Hello World" }));
The following example uses the built-in result types to customize the response:
app.MapGet("/hello", () => Results.Json(new { Message = "Hello World" }));
app.MapGet("/405", () => Results.StatusCode(405));
app.MapGet("/text", () => Results.Text("This is some text"));
app.MapGet("/old-path", () => Results.Redirect("/new-path"));
app.MapGet("/download", () => Results.File("myfile.text"));
Common result helpers exist in the Microsoft.AspNetCore.Http.Results static class.
| Description | Response type | Status Code | API |
|---|---|---|---|
| Write a JSON response with advanced options | application/json | 200 | Results.Json |
| Write a JSON response | application/json | 200 | Results.Ok |
| Write a text response | text/plain (default), configurable | 200 | Results.Text |
| Write the response as bytes | application/octet-stream (default), configurable | 200 | Results.Bytes |
| Write a stream of bytes to the response | application/octet-stream (default), configurable | 200 | Results.Stream |
| Stream a file to the response for download with the content-disposition header | application/octet-stream (default), configurable | 200 | Results.File |
| Set the status code to 404, with an optional JSON response | N/A | 404 | Results.NotFound |
| Set the status code to 204 | N/A | 204 | Results.NoContent |
| Set the status code to 422, with an optional JSON response | N/A | 422 | Results.UnprocessableEntity |
| Set the status code to 400, with an optional JSON response | N/A | 400 | Results.BadRequest |
| Set the status code to 409, with an optional JSON response | N/A | 409 | Results.Conflict |
| Write a problem details JSON object to the response | N/A | 500 (default), configurable | Results.Problem |
| Write a problem details JSON object to the response with validation errors | N/A | N/A, configurable | Results.ValidationProblem |
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:
We recommend adding an extension method to xref:Microsoft.AspNetCore.Http.IResultExtensions?displayProperty=fullName to make these custom results more discoverable.
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:
The preceding code can be written with xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization%2A:
The following sample uses policy-based authorization:
The [AllowAnonymous]
allows unauthenticated users to access endpoints:
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:
For more information, see xref:security/cors?view=aspnetcore-6.0
OpenAPI support in Minimal APIs
:::moniker-end