diff --git a/aspnetcore/release-notes/aspnetcore-7.0.md b/aspnetcore/release-notes/aspnetcore-7.0.md new file mode 100644 index 000000000000..bdcadbc760a9 --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7.0.md @@ -0,0 +1,60 @@ +--- +title: What's new in ASP.NET Core 7.0 +author: rick-anderson +description: Learn about the new features in ASP.NET Core 7.0. +ms.author: riande +ms.custom: mvc +ms.date: 10/29/2021 +uid: 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. + +## API controllers + +### Parameter binding with DI in API controllers + +Parameter binding for API controller actions binds parameters through [dependency injection](xref:fundamentals/dependency-injection) when the type is configured as a service. This means it’s no longer required to explicitly apply the [`[FromServices]`](xref:Microsoft.AspNetCore.Mvc.FromServicesAttribute) attribute to a parameter. In the following code, both actions return the time: + +[!code-csharp[](~/release-notes/aspnetcore-7/samples/ApiController/Controllers/MyController.cs?name=snippet)] + +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](/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions.disableimplicitfromservicesparameters?view=aspnetcore-7.0) `= true`: + +[!code-csharp[](~/release-notes/aspnetcore-7/samples/ApiController/Program.cs?name=snippet_dis&highlight=8-11)] + +In ASP.NET Core 7.0, types in DI are checked at app startup with 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: + +1. A previously specified [`BindingInfo.BindingSource`](xref:Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo.BindingSource) is never overwritten. +1. A complex type parameter, registered in the DI container, is assigned [`BindingSource.Services`](xref:Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource.Services). +1. A complex type parameter, not registered in the DI container, is assigned [`BindingSource.Body`](xref:Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource.Body). +1. A parameter with a name that appears as a route value in ***any*** route template is assigned [`BindingSource.Path`](xref:Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource.Path). +1. All other parameters are [`BindingSource.Query`](xref:Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource.Query). + +## 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 + +## IIS + +### Shadow copying in IIS + +Shadow copying app assemblies to the [ASP.NET Core Module (ANCM)](xref:host-and-deploy/aspnet-core-module) for IIS can provide a better end user experience than stopping the app by deploying an [app offline file](xref:host-and-deploy/iis/app-offline). + +For more information, see [Shadow copying in IIS](xref:host-and-deploy/iis/advanced?view=aspnetcore-7.0#shadow-copy) diff --git a/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/ApiController7.csproj b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/ApiController7.csproj new file mode 100644 index 000000000000..4c2bb77d0106 --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/ApiController7.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/Controllers/MyController.cs b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/Controllers/MyController.cs new file mode 100644 index 000000000000..916b6ff7197c --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/Controllers/MyController.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +namespace ApiController7.Controllers; + +#region snippet +[Route("[controller]")] +[ApiController] +public class MyController : ControllerBase +{ + public ActionResult GetWithAttribute([FromServices] IDateTime dateTime) + => Ok(dateTime.Now); + + [Route("noAttribute")] + public ActionResult Get(IDateTime dateTime) => Ok(dateTime.Now); +} +#endregion diff --git a/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/Program.cs b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/Program.cs new file mode 100644 index 000000000000..1eb6e0c8aaea --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/Program.cs @@ -0,0 +1,51 @@ +#define DIS // FIRST DIS MIN +#if NEVER +#elif FIRST +#region snippet1 +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddSingleton(); + +var app = builder.Build(); + +app.MapControllers(); + +app.Run(); +#endregion +#elif DIS +#region snippet_dis +using Microsoft.AspNetCore.Mvc; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddSingleton(); + +builder.Services.Configure(options => +{ + options.DisableImplicitFromServicesParameters = true; +}); + +var app = builder.Build(); + +app.MapControllers(); + +app.Run(); +#endregion +#elif MIN +// The following code works in .NET 6, not new to .NET 7 +#region snippet_min +using Microsoft.AspNetCore.Mvc; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddSingleton(); + +var app = builder.Build(); + +app.MapGet("/", ( IDateTime dateTime) => dateTime.Now); +app.MapGet("/fs", ([FromServices] IDateTime dateTime) => dateTime.Now); +app.Run(); +#endregion +#endif + diff --git a/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/SystemDateTime.cs b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/SystemDateTime.cs new file mode 100644 index 000000000000..8713098d1f94 --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/SystemDateTime.cs @@ -0,0 +1,9 @@ +public class SystemDateTime : IDateTime +{ + public string Now => DateTime.Now.ToString(); +} + +public interface IDateTime +{ + string Now { get; } +} \ No newline at end of file diff --git a/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/appsettings.Development.json b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/appsettings.Development.json new file mode 100644 index 000000000000..0c208ae9181e --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/appsettings.json b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/appsettings.json new file mode 100644 index 000000000000..10f68b8c8b4f --- /dev/null +++ b/aspnetcore/release-notes/aspnetcore-7/samples/ApiController/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}