14 KiB
title | author | description | ms.author | ms.custom | ms.date | uid |
---|---|---|---|---|---|---|
What's new in ASP.NET Core 7.0 | rick-anderson | Learn about the new features in ASP.NET Core 7.0. | riande | mvc | 10/29/2021 | aspnetcore-7 |
What's new in ASP.NET Core 7.0 preview
This article highlights the most significant changes in ASP.NET Core 7.0 with links to relevant documentation.
MVC and Razor pages
Support for nullable models in MVC views and Razor Pages
Nullable page or view models are supported to improve the experience when using null state checking with ASP.NET Core apps:
@model Product?
Bind with IParsable<T>.TryParse
in MVC and API Controllers
The IParsable<TSelf>.TryParse
API supports binding controller action parameter values. For more information, see Bind with IParsable<T>.TryParse
.
API controllers
Parameter binding with DI in API controllers
Parameter binding for API controller actions binds parameters through dependency injection when the type is configured as a service. This means it’s no longer required to explicitly apply the [FromServices]
attribute to a parameter. In the following code, both actions return the time:
In rare cases, automatic DI can break apps that have a type in DI that is also accepted in an API controllers action methods. It's not common to have a type in DI and as an argument in an API controller action. To disable automatic binding of parameters, set DisableImplicitFromServicesParameters
In ASP.NET Core 7.0, types in DI are checked at app startup with xref:Microsoft.Extensions.DependencyInjection.IServiceProviderIsService to determine if an argument in an API controller action comes from DI or from the other sources.
The new mechanism to infer binding source of API Controller action parameters uses the following rules:
- A previously specified
BindingInfo.BindingSource
is never overwritten. - A complex type parameter, registered in the DI container, is assigned
BindingSource.Services
. - A complex type parameter, not registered in the DI container, is assigned
BindingSource.Body
. - A parameter with a name that appears as a route value in any route template is assigned
BindingSource.Path
. - All other parameters are
BindingSource.Query
.
JSON property names in validation errors
By default, when an validation error occurs, model validation produces a xref:Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary with the property name as the error key. Some apps, such as single page apps, benefit from using JSON property names for validation errors generated from Web APIs. The following code configures validation to use the SystemTextJsonValidationMetadataProvider
to use JSON property names:
:::code language="csharp" source="~/mvc/models/validation/samples/7.x/ValidationJSON/Program.cs" id="snippet_1" highlight="5-8":::
The following code configures validation to use the NewtonsoftJsonValidationMetadataProvider
to use JSON property name when using Json.NET:
:::code language="csharp" source="~/mvc/models/validation/samples/7.x/ValidationJSON/Program.cs" id="snippet" highlight="5-8":::
For more information, see Use JSON property names in validation errors
Minimal APIs
Filters in Minimal API apps
Minimal API filters allow developers to implement business logic that supports:
- Running code before and after the route handler.
- Inspecting and modifying parameters provided during a route handler invocation.
- Intercepting the response behavior of a route handler.
Filters can be helpful in the following scenarios:
- Validating the request parameters and body that are sent to an endpoint.
- Logging information about the request and response.
- Validating that a request is targeting a supported API version.
For more information, see xref:fundamentals/minimal-apis/min-api-filters
Bind arrays and string values from headers and query strings
In ASP.NET 7, binding query strings to an array of primitive types, string arrays, and StringValues is supported:
Binding query strings or header values to an array of complex types is supported when the type has TryParse
implemented. For more information, see Bind arrays and string values from headers and query strings.
Bind the request body as a Stream
or PipeReader
The request body can bind as a Stream
or PipeReader
to efficiently support scenarios where the user has to process data and:
- Store the data to blob storage or enqueue the data to a queue provider.
- Process the stored data with a worker process or cloud function.
For example, the data might be enqueued to Azure Queue storage or stored in Azure Blob storage.
The following code implements a background queue:
The following code binds the request body to a Stream
:
The following code shows the complete Program.cs
file:
Limitations when binding request body to Stream
or PipeReader
:
- When reading data, the
Stream
is the same object asHttpRequest.Body
. - The request body isn’t buffered by default. After the body is read, it’s not rewindable. The stream can't be read multiple times.
- The
Stream
andPipeReader
aren't usable outside of the minimal action handler as the underlying buffers will be disposed or reused.
New Results.Stream overloads
We introduced new Results.Stream
overloads to accommodate scenarios that need access to the underlying HTTP response stream without buffering. These overloads also improve cases where an API streams data to the HTTP response stream, like from Azure Blob Storage. The following example uses ImageSharp to return a reduced size of the specified image:
For more information, see Stream examples
Typed results for minimal APIs
In .NET 6, the xref:Microsoft.AspNetCore.Http.IResult interface was introduced to represent values returned from minimal APIs that don’t utilize the implicit support for JSON serializing the returned object to the HTTP response. The static Results class is used to create varying IResult
objects that represent different types of responses. For example, setting the response status code or redirecting to another URL. The IResult
implementing framework types returned from these methods were internal however, making it difficult to verify the specific IResult
type being returned from methods in a unit test.
In .NET 7 the types implementing IResult
are public, allowing for type assertions when testing. For example:
OpenAPI improvements for minimal APIs
Microsoft.AspNetCore.OpenApi
NuGet package
The Microsoft.AspNetCore.OpenApi
package allows interactions with OpenAPI specifications for endpoints. The package acts as a link between the OpenAPI models that are defined in the Microsoft.AspNetCore.OpenApi
package and the endpoints that are defined in Minimal APIs. The package provides an API that examines an endpoint's parameters, responses, and metadata to construct an OpenAPI annotation type that is used to describe an endpoint.
Call WithOpenApi
with parameters
The WithOpenApi
method accepts a function that can be used to modify the OpenAPI annotation. For example, in the following code, a description is added to the first parameter of the endpoint:
Exclude Open API description
In the following sample, the /skipme
endpoint is excluded from generating an OpenAPI description:
Signal R
Dependency injection for SignalR hub methods
SignalR hub methods now support injecting services through dependency injection (DI).
Hub constructors can accept services from DI as parameters, which can be stored in properties on the class for use in a hub method. For more information, see Inject services into a hub
Performance
HTTP/2 Performance improvements
.NET 7 introduces a significant re-architecture of how Kestrel processes HTTP/2 requests. ASP.NET Core apps with busy HTTP/2 connections will experience reduced CPU usage and higher throughput.
Previously, the HTTP/2 multiplexing implementation relied on a lock controlling which request can write to the underlying TCP connection. A thread-safe queue replaces the write lock. Now, rather than fighting over which thread gets to use the write lock, requests now queue up and a dedicated consumer processes them. Previously wasted CPU resources are available to the rest of the app.
One place where these improvements can be noticed is in gRPC, a popular RPC framework that uses HTTP/2. Kestrel + gRPC benchmarks show a dramatic improvement:
Server
New ServerReady event for measuring startup time
The ServerReady
event has been added to measure startup time of ASP.NET Core apps.
IIS
Shadow copying in IIS
Shadow copying app assemblies to the ASP.NET Core Module (ANCM) for IIS can provide a better end user experience than stopping the app by deploying an app offline file.
For more information, see Shadow copying in IIS
Miscellaneous
dotnet watch
Improved console output for dotnet watch
The console output from dotnet watch has been improved to better align with the logging of ASP.NET Core and to stand out with 😮emojis😍.
Here’s an example of what the new output looks like:
See this GitHub pull request for more information.
Configure dotnet watch to always restart for rude edits
Rude edits are edits that can’t be hot reloaded. To configure dotnet watch to always restart without a prompt for rude edits, set the DOTNET_WATCH_RESTART_ON_RUDE_EDIT
environment variable to true
.
Developer exception page dark mode
Dark mode support has been added to the developer exception page, thanks to a contribution by Patrick Westerhoff. To test dark mode in a browser, from the developer tools page, set the mode to dark. For example, in Firefox:
In Chrome:
Project template option to use Program.Main method instead of top-level statements
The .NET 7 templates include an option to not use top-level statements and generate a namespace
and a Main
method declared on a Program
class.
Using the .NET CLI, use the --use-program-main
option:
dotnet new web --use-program-main
With Visual Studio, select the new Do not use top-level statements checkbox during project creation: