diff --git a/AspNetCore.sln b/AspNetCore.sln
index 86cea0758faf..44be86231669 100644
--- a/AspNetCore.sln
+++ b/AspNetCore.sln
@@ -1572,6 +1572,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BrowserTesting", "BrowserTe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.BrowserTesting", "src\Shared\BrowserTesting\src\Microsoft.AspNetCore.BrowserTesting.csproj", "{B739074E-6652-4F5B-B37E-775DC2245FEC}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{722E5A66-D84A-4689-AA87-7197FF5D7070}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapActionSample", "src\Http\Routing\samples\MapActionSample\MapActionSample.csproj", "{8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -7451,6 +7455,18 @@ Global
{B739074E-6652-4F5B-B37E-775DC2245FEC}.Release|x64.Build.0 = Release|Any CPU
{B739074E-6652-4F5B-B37E-775DC2245FEC}.Release|x86.ActiveCfg = Release|Any CPU
{B739074E-6652-4F5B-B37E-775DC2245FEC}.Release|x86.Build.0 = Release|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Debug|x64.Build.0 = Debug|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Debug|x86.Build.0 = Debug|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Release|x64.ActiveCfg = Release|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Release|x64.Build.0 = Release|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Release|x86.ActiveCfg = Release|Any CPU
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -8227,6 +8243,8 @@ Global
{22EA0993-8DFC-40C2-8481-8E85E21EFB56} = {41BB7BA4-AC08-4E9A-83EA-6D587A5B951C}
{8F33439F-5532-45D6-8A44-20EF9104AA9D} = {5F0044F2-4C66-46A8-BD79-075F001AA034}
{B739074E-6652-4F5B-B37E-775DC2245FEC} = {8F33439F-5532-45D6-8A44-20EF9104AA9D}
+ {722E5A66-D84A-4689-AA87-7197FF5D7070} = {54C42F57-5447-4C21-9812-4AF665567566}
+ {8F510BAA-FA6B-4648-8F98-28DF5C69DBB2} = {722E5A66-D84A-4689-AA87-7197FF5D7070}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}
diff --git a/src/Http/Http.Abstractions/src/IResult.cs b/src/Http/Http.Abstractions/src/IResult.cs
new file mode 100644
index 000000000000..a6c20a6ebded
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/IResult.cs
@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Http
+{
+ ///
+ /// Defines a contract that represents the result of an HTTP endpoint.
+ ///
+ public interface IResult
+ {
+ ///
+ /// Write an HTTP response reflecting the result.
+ ///
+ /// The for the current request.
+ /// A task that represents the asynchronous execute operation.
+ Task ExecuteAsync(HttpContext httpContext);
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Metadata/IFromBodyMetadata.cs b/src/Http/Http.Abstractions/src/Metadata/IFromBodyMetadata.cs
new file mode 100644
index 000000000000..878ec45dcc8a
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Metadata/IFromBodyMetadata.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Http.Metadata
+{
+ ///
+ /// Interface marking attributes that specify a parameter should be bound using the request body.
+ ///
+ public interface IFromBodyMetadata
+ {
+ ///
+ /// Gets whether empty input should be rejected or treated as valid.
+ ///
+ bool AllowEmpty => false;
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Metadata/IFromFormMetadata.cs b/src/Http/Http.Abstractions/src/Metadata/IFromFormMetadata.cs
new file mode 100644
index 000000000000..054628d50069
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Metadata/IFromFormMetadata.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Http.Metadata
+{
+ ///
+ /// Interface marking attributes that specify a parameter should be bound using form-data in the request body.
+ ///
+ public interface IFromFormMetadata
+ {
+ ///
+ /// The form field name.
+ ///
+ string? Name { get; }
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Metadata/IFromHeaderMetadata.cs b/src/Http/Http.Abstractions/src/Metadata/IFromHeaderMetadata.cs
new file mode 100644
index 000000000000..474daf9ed5bd
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Metadata/IFromHeaderMetadata.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Http.Metadata
+{
+ ///
+ /// Interface marking attributes that specify a parameter should be bound using the request headers.
+ ///
+ public interface IFromHeaderMetadata
+ {
+ ///
+ /// The request header name.
+ ///
+ string? Name { get; }
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Metadata/IFromQueryMetadata.cs b/src/Http/Http.Abstractions/src/Metadata/IFromQueryMetadata.cs
new file mode 100644
index 000000000000..303f70c8ed3e
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Metadata/IFromQueryMetadata.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Http.Metadata
+{
+ ///
+ /// Interface marking attributes that specify a parameter should be bound using the request query string.
+ ///
+ public interface IFromQueryMetadata
+ {
+ ///
+ /// The name of the query string field.
+ ///
+ string? Name { get; }
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Metadata/IFromRouteMetadata.cs b/src/Http/Http.Abstractions/src/Metadata/IFromRouteMetadata.cs
new file mode 100644
index 000000000000..66b24e5284e9
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Metadata/IFromRouteMetadata.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Http.Metadata
+{
+ ///
+ /// Interface marking attributes that specify a parameter should be bound using route-data from the current request.
+ ///
+ public interface IFromRouteMetadata
+ {
+ ///
+ /// The name.
+ ///
+ string? Name { get; }
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Metadata/IFromServiceMetadata.cs b/src/Http/Http.Abstractions/src/Metadata/IFromServiceMetadata.cs
new file mode 100644
index 000000000000..92c1e2ad6758
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Metadata/IFromServiceMetadata.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Http.Metadata
+{
+ ///
+ /// Interface marking attributes that specify a parameter should be bound using request services.
+ ///
+ public interface IFromServiceMetadata
+ {
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt b/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
index 86c4ecf1bf30..28f8d0317d61 100644
--- a/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
+++ b/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
@@ -4,6 +4,19 @@
*REMOVED*Microsoft.AspNetCore.Routing.RouteValueDictionary.TryAdd(string! key, object! value) -> bool
*REMOVED*static Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.UseMiddleware(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Type! middleware, params object![]! args) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
*REMOVED*static Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.UseMiddleware(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, params object![]! args) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
+Microsoft.AspNetCore.Http.IResult
+Microsoft.AspNetCore.Http.IResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task!
+Microsoft.AspNetCore.Http.Metadata.IFromBodyMetadata
+Microsoft.AspNetCore.Http.Metadata.IFromBodyMetadata.AllowEmpty.get -> bool
+Microsoft.AspNetCore.Http.Metadata.IFromFormMetadata
+Microsoft.AspNetCore.Http.Metadata.IFromFormMetadata.Name.get -> string?
+Microsoft.AspNetCore.Http.Metadata.IFromHeaderMetadata
+Microsoft.AspNetCore.Http.Metadata.IFromHeaderMetadata.Name.get -> string?
+Microsoft.AspNetCore.Http.Metadata.IFromQueryMetadata
+Microsoft.AspNetCore.Http.Metadata.IFromQueryMetadata.Name.get -> string?
+Microsoft.AspNetCore.Http.Metadata.IFromRouteMetadata
+Microsoft.AspNetCore.Http.Metadata.IFromRouteMetadata.Name.get -> string?
+Microsoft.AspNetCore.Http.Metadata.IFromServiceMetadata
Microsoft.AspNetCore.Http.Endpoint.Endpoint(Microsoft.AspNetCore.Http.RequestDelegate? requestDelegate, Microsoft.AspNetCore.Http.EndpointMetadataCollection? metadata, string? displayName) -> void
Microsoft.AspNetCore.Http.Endpoint.RequestDelegate.get -> Microsoft.AspNetCore.Http.RequestDelegate?
Microsoft.AspNetCore.Routing.RouteValueDictionary.TryAdd(string! key, object? value) -> bool
diff --git a/src/Http/Http/src/QueryCollection.cs b/src/Http/Http/src/QueryCollection.cs
index 75f1a47ea513..3753fd870bc7 100644
--- a/src/Http/Http/src/QueryCollection.cs
+++ b/src/Http/Http/src/QueryCollection.cs
@@ -24,7 +24,7 @@ public class QueryCollection : IQueryCollection
private static readonly IEnumerator> EmptyIEnumeratorType = EmptyEnumerator;
private static readonly IEnumerator EmptyIEnumerator = EmptyEnumerator;
- private Dictionary? Store { get; set; }
+ private Dictionary? Store { get; }
///
/// Initializes a new instance of .
diff --git a/src/Http/HttpAbstractions.slnf b/src/Http/HttpAbstractions.slnf
index 7c36d355ae50..61dd3673f847 100644
--- a/src/Http/HttpAbstractions.slnf
+++ b/src/Http/HttpAbstractions.slnf
@@ -1,53 +1,54 @@
-{
+{
"solution": {
"path": "..\\..\\AspNetCore.sln",
- "projects" : [
+ "projects": [
+ "src\\Hosting\\Abstractions\\src\\Microsoft.AspNetCore.Hosting.Abstractions.csproj",
+ "src\\Hosting\\Hosting\\src\\Microsoft.AspNetCore.Hosting.csproj",
+ "src\\Hosting\\Server.Abstractions\\src\\Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj",
+ "src\\Hosting\\TestHost\\src\\Microsoft.AspNetCore.TestHost.csproj",
"src\\Http\\Authentication.Abstractions\\src\\Microsoft.AspNetCore.Authentication.Abstractions.csproj",
"src\\Http\\Authentication.Core\\src\\Microsoft.AspNetCore.Authentication.Core.csproj",
"src\\Http\\Authentication.Core\\test\\Microsoft.AspNetCore.Authentication.Core.Test.csproj",
"src\\Http\\Headers\\src\\Microsoft.Net.Http.Headers.csproj",
"src\\Http\\Headers\\test\\Microsoft.Net.Http.Headers.Tests.csproj",
- "src\\Http\\Http\\src\\Microsoft.AspNetCore.Http.csproj",
- "src\\Http\\Http\\test\\Microsoft.AspNetCore.Http.Tests.csproj",
"src\\Http\\Http.Abstractions\\src\\Microsoft.AspNetCore.Http.Abstractions.csproj",
"src\\Http\\Http.Abstractions\\test\\Microsoft.AspNetCore.Http.Abstractions.Tests.csproj",
"src\\Http\\Http.Extensions\\src\\Microsoft.AspNetCore.Http.Extensions.csproj",
"src\\Http\\Http.Extensions\\test\\Microsoft.AspNetCore.Http.Extensions.Tests.csproj",
"src\\Http\\Http.Features\\src\\Microsoft.AspNetCore.Http.Features.csproj",
"src\\Http\\Http.Features\\test\\Microsoft.AspNetCore.Http.Features.Tests.csproj",
+ "src\\Http\\Http\\perf\\Microsoft.AspNetCore.Http.Performance.csproj",
+ "src\\Http\\Http\\src\\Microsoft.AspNetCore.Http.csproj",
+ "src\\Http\\Http\\test\\Microsoft.AspNetCore.Http.Tests.csproj",
+ "src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj",
"src\\Http\\Owin\\src\\Microsoft.AspNetCore.Owin.csproj",
"src\\Http\\Owin\\test\\Microsoft.AspNetCore.Owin.Tests.csproj",
- "src\\Http\\samples\\SampleApp\\HttpAbstractions.SampleApp.csproj",
- "src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
- "src\\Http\\WebUtilities\\test\\Microsoft.AspNetCore.WebUtilities.Tests.csproj",
- "src\\Http\\Http\\perf\\Microsoft.AspNetCore.Http.Performance.csproj",
+ "src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj",
+ "src\\Http\\Routing.Abstractions\\test\\Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests.csproj",
"src\\Http\\Routing\\perf\\Microsoft.AspNetCore.Routing.Performance.csproj",
+ "src\\Http\\Routing\\samples\\MapActionSample\\MapActionSample.csproj",
"src\\Http\\Routing\\src\\Microsoft.AspNetCore.Routing.csproj",
"src\\Http\\Routing\\test\\FunctionalTests\\Microsoft.AspNetCore.Routing.FunctionalTests.csproj",
"src\\Http\\Routing\\test\\UnitTests\\Microsoft.AspNetCore.Routing.Tests.csproj",
- "src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj",
- "src\\Http\\Routing.Abstractions\\test\\Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests.csproj",
- "src\\Hosting\\TestHost\\src\\Microsoft.AspNetCore.TestHost.csproj",
- "src\\Http\\Routing\\test\\testassets\\RoutingWebSite\\RoutingWebSite.csproj",
- "src\\Http\\Routing\\test\\testassets\\RoutingSandbox\\RoutingSandbox.csproj",
"src\\Http\\Routing\\test\\testassets\\Benchmarks\\Benchmarks.csproj",
- "src\\Servers\\Kestrel\\Kestrel\\src\\Microsoft.AspNetCore.Server.Kestrel.csproj",
- "src\\Middleware\\StaticFiles\\src\\Microsoft.AspNetCore.StaticFiles.csproj",
- "src\\Servers\\Kestrel\\Core\\src\\Microsoft.AspNetCore.Server.Kestrel.Core.csproj",
- "src\\Hosting\\Hosting\\src\\Microsoft.AspNetCore.Hosting.csproj",
- "src\\Servers\\Connections.Abstractions\\src\\Microsoft.AspNetCore.Connections.Abstractions.csproj",
- "src\\Hosting\\Abstractions\\src\\Microsoft.AspNetCore.Hosting.Abstractions.csproj",
- "src\\Hosting\\Server.Abstractions\\src\\Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj",
- "src\\Servers\\Kestrel\\Transport.Sockets\\src\\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj",
- "src\\Middleware\\HttpOverrides\\src\\Microsoft.AspNetCore.HttpOverrides.csproj",
- "src\\Servers\\IIS\\IISIntegration\\src\\Microsoft.AspNetCore.Server.IISIntegration.csproj",
+ "src\\Http\\Routing\\test\\testassets\\RoutingSandbox\\RoutingSandbox.csproj",
+ "src\\Http\\Routing\\test\\testassets\\RoutingWebSite\\RoutingWebSite.csproj",
"src\\Http\\WebUtilities\\perf\\Microsoft.AspNetCore.WebUtilities.Performance\\Microsoft.AspNetCore.WebUtilities.Performance.csproj",
- "src\\Security\\Authorization\\Policy\\src\\Microsoft.AspNetCore.Authorization.Policy.csproj",
+ "src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
+ "src\\Http\\WebUtilities\\test\\Microsoft.AspNetCore.WebUtilities.Tests.csproj",
+ "src\\Http\\samples\\SampleApp\\HttpAbstractions.SampleApp.csproj",
"src\\Middleware\\CORS\\src\\Microsoft.AspNetCore.Cors.csproj",
- "src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj",
+ "src\\Middleware\\HttpOverrides\\src\\Microsoft.AspNetCore.HttpOverrides.csproj",
+ "src\\Middleware\\StaticFiles\\src\\Microsoft.AspNetCore.StaticFiles.csproj",
"src\\ObjectPool\\src\\Microsoft.Extensions.ObjectPool.csproj",
- "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj",
- "src\\Testing\\src\\Microsoft.AspNetCore.Testing.csproj"
+ "src\\Security\\Authorization\\Policy\\src\\Microsoft.AspNetCore.Authorization.Policy.csproj",
+ "src\\Servers\\Connections.Abstractions\\src\\Microsoft.AspNetCore.Connections.Abstractions.csproj",
+ "src\\Servers\\IIS\\IISIntegration\\src\\Microsoft.AspNetCore.Server.IISIntegration.csproj",
+ "src\\Servers\\Kestrel\\Core\\src\\Microsoft.AspNetCore.Server.Kestrel.Core.csproj",
+ "src\\Servers\\Kestrel\\Kestrel\\src\\Microsoft.AspNetCore.Server.Kestrel.csproj",
+ "src\\Servers\\Kestrel\\Transport.Sockets\\src\\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj",
+ "src\\Testing\\src\\Microsoft.AspNetCore.Testing.csproj",
+ "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj"
]
}
-}
+}
\ No newline at end of file
diff --git a/src/Http/Routing/samples/MapActionSample/MapActionSample.csproj b/src/Http/Routing/samples/MapActionSample/MapActionSample.csproj
new file mode 100644
index 000000000000..6b59d1446b9b
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/MapActionSample.csproj
@@ -0,0 +1,16 @@
+
+
+
+ $(DefaultNetCoreTargetFramework)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Http/Routing/samples/MapActionSample/Program.cs b/src/Http/Routing/samples/MapActionSample/Program.cs
new file mode 100644
index 000000000000..0e33ff8e1f6f
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/Program.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace HttpApiSampleApp
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/src/Http/Routing/samples/MapActionSample/Properties/launchSettings.json b/src/Http/Routing/samples/MapActionSample/Properties/launchSettings.json
new file mode 100644
index 000000000000..af085af38a7e
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/Properties/launchSettings.json
@@ -0,0 +1,13 @@
+{
+ "profiles": {
+ "HttpApiSampleApp": {
+ "commandName": "Project",
+ "dotnetRunMessages": "true",
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/src/Http/Routing/samples/MapActionSample/Startup.cs b/src/Http/Routing/samples/MapActionSample/Startup.cs
new file mode 100644
index 000000000000..2efb7dd71e5b
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/Startup.cs
@@ -0,0 +1,49 @@
+using System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace HttpApiSampleApp
+{
+ public class Startup
+ {
+ // This method gets called by the runtime. Use this method to add services to the container.
+ // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+ public void ConfigureServices(IServiceCollection services)
+ {
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ [HttpPost("/EchoTodo")]
+ JsonResult EchoTodo([FromBody] Todo todo) => new(todo);
+
+ endpoints.MapAction((Func)EchoTodo);
+
+ endpoints.MapPost("/EchoTodoProto", async httpContext =>
+ {
+ var todo = await httpContext.Request.ReadFromJsonAsync();
+ await httpContext.Response.WriteAsJsonAsync(todo);
+ });
+
+ endpoints.MapGet("/", async context =>
+ {
+ await context.Response.WriteAsync("Hello World!");
+ });
+ });
+ }
+ }
+}
diff --git a/src/Http/Routing/samples/MapActionSample/Todo.cs b/src/Http/Routing/samples/MapActionSample/Todo.cs
new file mode 100644
index 000000000000..2bcc698c8e5a
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/Todo.cs
@@ -0,0 +1,9 @@
+namespace HttpApiSampleApp
+{
+ public class Todo
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public bool IsComplete { get; set; }
+ }
+}
diff --git a/src/Http/Routing/samples/MapActionSample/appsettings.Development.json b/src/Http/Routing/samples/MapActionSample/appsettings.Development.json
new file mode 100644
index 000000000000..8983e0fc1c5e
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/src/Http/Routing/samples/MapActionSample/appsettings.json b/src/Http/Routing/samples/MapActionSample/appsettings.json
new file mode 100644
index 000000000000..d9d9a9bff6fd
--- /dev/null
+++ b/src/Http/Routing/samples/MapActionSample/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/Http/Routing/src/Builder/MapActionEndpointConventionBuilder.cs b/src/Http/Routing/src/Builder/MapActionEndpointConventionBuilder.cs
new file mode 100644
index 000000000000..4491b0305739
--- /dev/null
+++ b/src/Http/Routing/src/Builder/MapActionEndpointConventionBuilder.cs
@@ -0,0 +1,33 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.AspNetCore.Builder
+{
+ ///
+ /// Builds conventions that will be used for customization of MapAction instances.
+ ///
+ public sealed class MapActionEndpointConventionBuilder : IEndpointConventionBuilder
+ {
+ private readonly List _endpointConventionBuilders;
+
+ internal MapActionEndpointConventionBuilder(List endpointConventionBuilders)
+ {
+ _endpointConventionBuilders = endpointConventionBuilders;
+ }
+
+ ///
+ /// Adds the specified convention to the builder. Conventions are used to customize instances.
+ ///
+ /// The convention to add to the builder.
+ public void Add(Action convention)
+ {
+ foreach (var endpointConventionBuilder in _endpointConventionBuilders)
+ {
+ endpointConventionBuilder.Add(convention);
+ }
+ }
+ }
+}
diff --git a/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs b/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs
new file mode 100644
index 000000000000..e132e673ea32
--- /dev/null
+++ b/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs
@@ -0,0 +1,80 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.AspNetCore.Routing.Internal;
+
+namespace Microsoft.AspNetCore.Builder
+{
+ ///
+ /// Provides extension methods for to define HTTP API endpoints.
+ ///
+ public static class MapActionEndpointRouteBuilderExtensions
+ {
+ ///
+ /// Adds a to the that matches the pattern specified via attributes.
+ ///
+ /// The to add the route to.
+ /// The delegate executed when the endpoint is matched.
+ /// An that can be used to further customize the endpoint.
+ public static MapActionEndpointConventionBuilder MapAction(
+ this IEndpointRouteBuilder endpoints,
+ Delegate action)
+ {
+ if (endpoints is null)
+ {
+ throw new ArgumentNullException(nameof(endpoints));
+ }
+
+ if (action is null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+
+ var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(action);
+
+ var routeAttributes = action.Method.GetCustomAttributes().OfType();
+ var conventionBuilders = new List();
+
+ const int defaultOrder = 0;
+
+ foreach (var routeAttribute in routeAttributes)
+ {
+ if (routeAttribute.RoutePattern is not string pattern)
+ {
+ continue;
+ }
+
+ var routeName = (routeAttribute as IRouteNameMetadata)?.RouteName;
+ var routeOrder = (routeAttribute as IRouteOrderMetadata)?.RouteOrder;
+
+ var conventionBuilder = endpoints.Map(pattern, requestDelegate);
+
+ conventionBuilder.Add(endpointBuilder =>
+ {
+ foreach (var attribute in action.Method.GetCustomAttributes())
+ {
+ endpointBuilder.Metadata.Add(attribute);
+ }
+
+ endpointBuilder.DisplayName = routeName ?? pattern;
+
+ ((RouteEndpointBuilder)endpointBuilder).Order = routeOrder ?? defaultOrder;
+ });
+
+ conventionBuilders.Add(conventionBuilder);
+ }
+
+ if (conventionBuilders.Count == 0)
+ {
+ throw new InvalidOperationException("Action must have a pattern. Is it missing a Route attribute?");
+ }
+
+ return new MapActionEndpointConventionBuilder(conventionBuilders);
+ }
+ }
+}
diff --git a/src/Http/Routing/src/IRouteOrderMetadata.cs b/src/Http/Routing/src/IRouteOrderMetadata.cs
new file mode 100644
index 000000000000..4326b24e5625
--- /dev/null
+++ b/src/Http/Routing/src/IRouteOrderMetadata.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Routing
+{
+ ///
+ /// Interface for attributes which can supply a route order for attribute routing.
+ ///
+ public interface IRouteOrderMetadata
+ {
+ ///
+ /// Gets the route order. The order determines the order of route execution. Routes with a lower
+ /// order value are tried first. When a route doesn't specify a value, it gets a default value of 0.
+ /// A null value for the Order property means that the user didn't specify an explicit order for the
+ /// route.
+ ///
+ int? RouteOrder { get; }
+ }
+}
diff --git a/src/Http/Routing/src/IRoutePatternMetadata.cs b/src/Http/Routing/src/IRoutePatternMetadata.cs
new file mode 100644
index 000000000000..615a67abfbeb
--- /dev/null
+++ b/src/Http/Routing/src/IRoutePatternMetadata.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Routing
+{
+ ///
+ /// Interface for attributes which can supply a route pattern for attribute routing.
+ ///
+ public interface IRoutePatternMetadata
+ {
+ ///
+ /// The route pattern. May be .
+ ///
+ string? RoutePattern { get; }
+ }
+}
diff --git a/src/Http/Routing/src/Internal/MapActionExpressionTreeBuilder.cs b/src/Http/Routing/src/Internal/MapActionExpressionTreeBuilder.cs
new file mode 100644
index 000000000000..10be2443b5e7
--- /dev/null
+++ b/src/Http/Routing/src/Internal/MapActionExpressionTreeBuilder.cs
@@ -0,0 +1,463 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Metadata;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Internal;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Routing.Internal
+{
+ internal static class MapActionExpressionTreeBuilder
+ {
+ private static readonly MethodInfo ChangeTypeMethodInfo = GetMethodInfo>((value, type) => Convert.ChangeType(value, type, CultureInfo.InvariantCulture));
+ private static readonly MethodInfo ExecuteTaskOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteTask), BindingFlags.NonPublic | BindingFlags.Static)!;
+ private static readonly MethodInfo ExecuteValueTaskOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteValueTask), BindingFlags.NonPublic | BindingFlags.Static)!;
+ private static readonly MethodInfo ExecuteTaskResultOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteTaskResult), BindingFlags.NonPublic | BindingFlags.Static)!;
+ private static readonly MethodInfo ExecuteValueResultTaskOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteValueTaskResult), BindingFlags.NonPublic | BindingFlags.Static)!;
+ private static readonly MethodInfo GetRequiredServiceMethodInfo = typeof(ServiceProviderServiceExtensions).GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService), BindingFlags.Public | BindingFlags.Static, new Type[] { typeof(IServiceProvider) })!;
+ private static readonly MethodInfo ResultWriteResponseAsync = typeof(IResult).GetMethod(nameof(IResult.ExecuteAsync), BindingFlags.Public | BindingFlags.Instance)!;
+ private static readonly MethodInfo StringResultWriteResponseAsync = GetMethodInfo>((response, text) => HttpResponseWritingExtensions.WriteAsync(response, text, default));
+ private static readonly MethodInfo JsonResultWriteResponseAsync = GetMethodInfo>((response, value) => HttpResponseJsonExtensions.WriteAsJsonAsync(response, value, default));
+ private static readonly MemberInfo CompletedTaskMemberInfo = GetMemberInfo>(() => Task.CompletedTask);
+
+ private static readonly ParameterExpression TargetArg = Expression.Parameter(typeof(object), "target");
+ private static readonly ParameterExpression HttpContextParameter = Expression.Parameter(typeof(HttpContext), "httpContext");
+ private static readonly ParameterExpression DeserializedBodyArg = Expression.Parameter(typeof(object), "bodyValue");
+
+ private static readonly MemberExpression RequestServicesExpr = Expression.Property(HttpContextParameter, nameof(HttpContext.RequestServices));
+ private static readonly MemberExpression HttpRequestExpr = Expression.Property(HttpContextParameter, nameof(HttpContext.Request));
+ private static readonly MemberExpression HttpResponseExpr = Expression.Property(HttpContextParameter, nameof(HttpContext.Response));
+
+ public static RequestDelegate BuildRequestDelegate(Delegate action)
+ {
+ // Non void return type
+
+ // Task Invoke(HttpContext httpContext)
+ // {
+ // // Action parameters are bound from the request, services, etc... based on attribute and type information.
+ // return ExecuteTask(action(...), httpContext);
+ // }
+
+ // void return type
+
+ // Task Invoke(HttpContext httpContext)
+ // {
+ // action(...);
+ // return default;
+ // }
+
+ var method = action.Method;
+
+ var consumeBodyDirectly = false;
+ var consumeBodyAsForm = false;
+ Type? bodyType = null;
+ var allowEmptyBody = false;
+
+ // This argument represents the deserialized body returned from IHttpRequestReader
+ // when the method has a FromBody attribute declared
+
+ var args = new List();
+
+ foreach (var parameter in method.GetParameters())
+ {
+ Expression paramterExpression = Expression.Default(parameter.ParameterType);
+
+ if (parameter.GetCustomAttributes().OfType().FirstOrDefault() is { } routeAttribute)
+ {
+ var routeValuesProperty = Expression.Property(HttpRequestExpr, nameof(HttpRequest.RouteValues));
+ paramterExpression = BindParamenter(routeValuesProperty, parameter, routeAttribute.Name);
+ }
+ else if (parameter.GetCustomAttributes().OfType().FirstOrDefault() is { } queryAttribute)
+ {
+ var queryProperty = Expression.Property(HttpRequestExpr, nameof(HttpRequest.Query));
+ paramterExpression = BindParamenter(queryProperty, parameter, queryAttribute.Name);
+ }
+ else if (parameter.GetCustomAttributes().OfType().FirstOrDefault() is { } headerAttribute)
+ {
+ var headersProperty = Expression.Property(HttpRequestExpr, nameof(HttpRequest.Headers));
+ paramterExpression = BindParamenter(headersProperty, parameter, headerAttribute.Name);
+ }
+ else if (parameter.GetCustomAttributes().OfType().FirstOrDefault() is { } bodyAttribute)
+ {
+ if (consumeBodyDirectly)
+ {
+ throw new InvalidOperationException("Action cannot have more than one FromBody attribute.");
+ }
+
+ if (consumeBodyAsForm)
+ {
+ ThrowCannotReadBodyDirectlyAndAsForm();
+ }
+
+ consumeBodyDirectly = true;
+ allowEmptyBody = bodyAttribute.AllowEmpty;
+ bodyType = parameter.ParameterType;
+ paramterExpression = Expression.Convert(DeserializedBodyArg, bodyType);
+ }
+ else if (parameter.GetCustomAttributes().OfType().FirstOrDefault() is { } formAttribute)
+ {
+ if (consumeBodyDirectly)
+ {
+ ThrowCannotReadBodyDirectlyAndAsForm();
+ }
+
+ consumeBodyAsForm = true;
+
+ var formProperty = Expression.Property(HttpRequestExpr, nameof(HttpRequest.Form));
+ paramterExpression = BindParamenter(formProperty, parameter, parameter.Name);
+ }
+ else if (parameter.CustomAttributes.Any(a => typeof(IFromServiceMetadata).IsAssignableFrom(a.AttributeType)))
+ {
+ paramterExpression = Expression.Call(GetRequiredServiceMethodInfo.MakeGenericMethod(parameter.ParameterType), RequestServicesExpr);
+ }
+ else
+ {
+ if (parameter.ParameterType == typeof(IFormCollection))
+ {
+ if (consumeBodyDirectly)
+ {
+ ThrowCannotReadBodyDirectlyAndAsForm();
+ }
+
+ consumeBodyAsForm = true;
+
+ paramterExpression = Expression.Property(HttpRequestExpr, nameof(HttpRequest.Form));
+ }
+ else if (parameter.ParameterType == typeof(HttpContext))
+ {
+ paramterExpression = HttpContextParameter;
+ }
+ }
+
+ args.Add(paramterExpression);
+ }
+
+ Expression? body = null;
+
+ MethodCallExpression methodCall;
+
+ if (action.Target is null)
+ {
+ methodCall = Expression.Call(method, args);
+ }
+ else
+ {
+ var castedTarget = Expression.Convert(TargetArg, action.Target.GetType());
+ methodCall = Expression.Call(castedTarget, method, args);
+ }
+
+ // Exact request delegate match
+ if (method.ReturnType == typeof(void))
+ {
+ var bodyExpressions = new List
+ {
+ methodCall,
+ Expression.Property(null, (PropertyInfo)CompletedTaskMemberInfo)
+ };
+
+ body = Expression.Block(bodyExpressions);
+ }
+ else if (AwaitableInfo.IsTypeAwaitable(method.ReturnType, out var info))
+ {
+ if (method.ReturnType == typeof(Task))
+ {
+ body = methodCall;
+ }
+ else if (method.ReturnType.IsGenericType &&
+ method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
+ {
+ var typeArg = method.ReturnType.GetGenericArguments()[0];
+
+ if (typeof(IResult).IsAssignableFrom(typeArg))
+ {
+ body = Expression.Call(
+ ExecuteTaskResultOfTMethodInfo.MakeGenericMethod(typeArg),
+ methodCall,
+ TargetArg,
+ HttpContextParameter);
+ }
+ else
+ {
+ // ExecuteTask(action(..), httpContext);
+ body = Expression.Call(
+ ExecuteTaskOfTMethodInfo.MakeGenericMethod(typeArg),
+ methodCall,
+ TargetArg,
+ HttpContextParameter);
+ }
+ }
+ else if (method.ReturnType.IsGenericType &&
+ method.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>))
+ {
+ var typeArg = method.ReturnType.GetGenericArguments()[0];
+
+ if (typeof(IResult).IsAssignableFrom(typeArg))
+ {
+ body = Expression.Call(
+ ExecuteValueResultTaskOfTMethodInfo.MakeGenericMethod(typeArg),
+ methodCall,
+ TargetArg,
+ HttpContextParameter);
+ }
+ else
+ {
+ // ExecuteTask(action(..), httpContext);
+ body = Expression.Call(
+ ExecuteValueTaskOfTMethodInfo.MakeGenericMethod(typeArg),
+ methodCall,
+ TargetArg,
+ HttpContextParameter);
+ }
+ }
+ else
+ {
+ // TODO: Handle custom awaitables
+ throw new NotSupportedException($"Unsupported return type: {method.ReturnType}");
+ }
+ }
+ else if (typeof(IResult).IsAssignableFrom(method.ReturnType))
+ {
+ body = Expression.Call(methodCall, ResultWriteResponseAsync, HttpContextParameter);
+ }
+ else if (method.ReturnType == typeof(string))
+ {
+ body = Expression.Call(StringResultWriteResponseAsync, HttpResponseExpr, methodCall, Expression.Constant(CancellationToken.None));
+ }
+ else
+ {
+ body = Expression.Call(JsonResultWriteResponseAsync, HttpResponseExpr, methodCall, Expression.Constant(CancellationToken.None));
+ }
+
+ Func
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public sealed class AcceptVerbsAttribute : Attribute, IActionHttpMethodProvider, IRouteTemplateProvider
+ public sealed class AcceptVerbsAttribute : Attribute, IHttpMethodMetadata, IActionHttpMethodProvider, IRouteTemplateProvider
{
+ private readonly List _httpMethods;
+
private int? _order;
///
@@ -35,13 +38,16 @@ public AcceptVerbsAttribute(string method)
/// The HTTP methods the action supports.
public AcceptVerbsAttribute(params string[] methods)
{
- HttpMethods = methods.Select(method => method.ToUpperInvariant());
+ _httpMethods = methods.Select(method => method.ToUpperInvariant()).ToList();
}
///
/// Gets the HTTP methods the action supports.
///
- public IEnumerable HttpMethods { get; }
+ public IEnumerable HttpMethods => _httpMethods;
+
+ IReadOnlyList IHttpMethodMetadata.HttpMethods => _httpMethods;
+ bool IHttpMethodMetadata.AcceptCorsPreflight => false;
///
/// The route template. May be null.
@@ -69,4 +75,4 @@ public int Order
///
public string Name { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Mvc/Mvc.Core/src/FromBodyAttribute.cs b/src/Mvc/Mvc.Core/src/FromBodyAttribute.cs
index 9894666c7de9..c3d1b46f3ddc 100644
--- a/src/Mvc/Mvc.Core/src/FromBodyAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/FromBodyAttribute.cs
@@ -3,6 +3,7 @@
using System;
using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Http.Metadata;
namespace Microsoft.AspNetCore.Mvc
{
@@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc
/// Specifies that a parameter or property should be bound using the request body.
///
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
- public class FromBodyAttribute : Attribute, IBindingSourceMetadata, IConfigureEmptyBodyBehavior
+ public class FromBodyAttribute : Attribute, IBindingSourceMetadata, IConfigureEmptyBodyBehavior, IFromBodyMetadata
{
///
public BindingSource BindingSource => BindingSource.Body;
@@ -24,5 +25,9 @@ public class FromBodyAttribute : Attribute, IBindingSourceMetadata, IConfigureEm
/// Specifying or will override the framework defaults.
///
public EmptyBodyBehavior EmptyBodyBehavior { get; set; }
+
+ // Since the default behavior is to reject empty bodies if MvcOptions.AllowEmptyInputInBodyModelBinding is not configured,
+ // we'll consider EmptyBodyBehavior.Default the same as EmptyBodyBehavior.Disallow.
+ bool IFromBodyMetadata.AllowEmpty => EmptyBodyBehavior == EmptyBodyBehavior.Allow;
}
}
diff --git a/src/Mvc/Mvc.Core/src/FromFormAttribute.cs b/src/Mvc/Mvc.Core/src/FromFormAttribute.cs
index a42774f17f46..41e7823ea52b 100644
--- a/src/Mvc/Mvc.Core/src/FromFormAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/FromFormAttribute.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc
@@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc
/// Specifies that a parameter or property should be bound using form-data in the request body.
///
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
- public class FromFormAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider
+ public class FromFormAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider, IFromFormMetadata
{
///
public BindingSource BindingSource => BindingSource.Form;
diff --git a/src/Mvc/Mvc.Core/src/FromHeaderAttribute.cs b/src/Mvc/Mvc.Core/src/FromHeaderAttribute.cs
index 46809454f1cc..c4331287d84a 100644
--- a/src/Mvc/Mvc.Core/src/FromHeaderAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/FromHeaderAttribute.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc
@@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc
/// Specifies that a parameter or property should be bound using the request headers.
///
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
- public class FromHeaderAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider
+ public class FromHeaderAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider, IFromHeaderMetadata
{
///
public BindingSource BindingSource => BindingSource.Header;
diff --git a/src/Mvc/Mvc.Core/src/FromQueryAttribute.cs b/src/Mvc/Mvc.Core/src/FromQueryAttribute.cs
index df82f67bc322..9f594a27bd9d 100644
--- a/src/Mvc/Mvc.Core/src/FromQueryAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/FromQueryAttribute.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc
@@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc
/// Specifies that a parameter or property should be bound using the request query string.
///
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
- public class FromQueryAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider
+ public class FromQueryAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider, IFromQueryMetadata
{
///
public BindingSource BindingSource => BindingSource.Query;
diff --git a/src/Mvc/Mvc.Core/src/FromRouteAttribute.cs b/src/Mvc/Mvc.Core/src/FromRouteAttribute.cs
index 94952e502f55..a257d8ffa93e 100644
--- a/src/Mvc/Mvc.Core/src/FromRouteAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/FromRouteAttribute.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc
@@ -10,12 +12,14 @@ namespace Microsoft.AspNetCore.Mvc
/// Specifies that a parameter or property should be bound using route-data from the current request.
///
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
- public class FromRouteAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider
+ public class FromRouteAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider, IFromRouteMetadata
{
///
public BindingSource BindingSource => BindingSource.Path;
- ///
+ ///
+ /// The name.
+ ///
public string Name { get; set; }
}
}
diff --git a/src/Mvc/Mvc.Core/src/FromServicesAttribute.cs b/src/Mvc/Mvc.Core/src/FromServicesAttribute.cs
index 31e299de7373..41c993429383 100644
--- a/src/Mvc/Mvc.Core/src/FromServicesAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/FromServicesAttribute.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc
@@ -23,7 +24,7 @@ namespace Microsoft.AspNetCore.Mvc
///
///
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
- public class FromServicesAttribute : Attribute, IBindingSourceMetadata
+ public class FromServicesAttribute : Attribute, IBindingSourceMetadata, IFromServiceMetadata
{
///
public BindingSource BindingSource => BindingSource.Services;
diff --git a/src/Mvc/Mvc.Core/src/JsonResult.cs b/src/Mvc/Mvc.Core/src/JsonResult.cs
index 6d43cc68323e..d4b23097e969 100644
--- a/src/Mvc/Mvc.Core/src/JsonResult.cs
+++ b/src/Mvc/Mvc.Core/src/JsonResult.cs
@@ -4,6 +4,7 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
@@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc
///
/// An action result which formats the given object as JSON.
///
- public class JsonResult : ActionResult, IStatusCodeActionResult
+ public class JsonResult : ActionResult, IResult, IStatusCodeActionResult
{
///
/// Creates a new with the given .
@@ -80,5 +81,15 @@ public override Task ExecuteResultAsync(ActionContext context)
var executor = services.GetRequiredService>();
return executor.ExecuteAsync(context, this);
}
+
+ ///
+ /// Write the result as JSON to the HTTP response.
+ ///
+ /// The for the current request.
+ /// A task that represents the asynchronous execute operation.
+ Task IResult.ExecuteAsync(HttpContext httpContext)
+ {
+ return httpContext.Response.WriteAsJsonAsync(Value);
+ }
}
}
diff --git a/src/Mvc/Mvc.Core/src/Routing/HttpMethodAttribute.cs b/src/Mvc/Mvc.Core/src/Routing/HttpMethodAttribute.cs
index 1c204f9cf470..dd0d25b6e4b9 100644
--- a/src/Mvc/Mvc.Core/src/Routing/HttpMethodAttribute.cs
+++ b/src/Mvc/Mvc.Core/src/Routing/HttpMethodAttribute.cs
@@ -6,6 +6,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Mvc.Routing
{
@@ -13,8 +15,10 @@ namespace Microsoft.AspNetCore.Mvc.Routing
/// Identifies an action that supports a given set of HTTP methods.
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public abstract class HttpMethodAttribute : Attribute, IActionHttpMethodProvider, IRouteTemplateProvider
+ public abstract class HttpMethodAttribute : Attribute, IHttpMethodMetadata, IActionHttpMethodProvider, IRouteTemplateProvider
{
+ private readonly List _httpMethods;
+
private int? _order;
///
@@ -40,12 +44,15 @@ public HttpMethodAttribute(IEnumerable httpMethods, string? template)
throw new ArgumentNullException(nameof(httpMethods));
}
- HttpMethods = httpMethods;
+ _httpMethods = httpMethods.ToList();
Template = template;
}
///
- public IEnumerable HttpMethods { get; }
+ public IEnumerable HttpMethods => _httpMethods;
+
+ IReadOnlyList IHttpMethodMetadata.HttpMethods => _httpMethods;
+ bool IHttpMethodMetadata.AcceptCorsPreflight => false;
///
public string? Template { get; }
@@ -68,5 +75,6 @@ public int Order
///
[DisallowNull]
public string? Name { get; set; }
+
}
}
diff --git a/src/Mvc/Mvc.Core/src/Routing/IRouteTemplateProvider.cs b/src/Mvc/Mvc.Core/src/Routing/IRouteTemplateProvider.cs
index 0934bad99f24..f15e76abc64c 100644
--- a/src/Mvc/Mvc.Core/src/Routing/IRouteTemplateProvider.cs
+++ b/src/Mvc/Mvc.Core/src/Routing/IRouteTemplateProvider.cs
@@ -3,12 +3,14 @@
#nullable enable
+using Microsoft.AspNetCore.Routing;
+
namespace Microsoft.AspNetCore.Mvc.Routing
{
///
/// Interface for attributes which can supply a route template for attribute routing.
///
- public interface IRouteTemplateProvider
+ public interface IRouteTemplateProvider : IRoutePatternMetadata, IRouteOrderMetadata, IRouteNameMetadata
{
///
/// The route template. May be .
@@ -28,5 +30,14 @@ public interface IRouteTemplateProvider
/// of relying on selection of a route based on the given set of route values.
///
string? Name { get; }
+
+ ///
+ string? IRoutePatternMetadata.RoutePattern => Template;
+
+ ///
+ int? IRouteOrderMetadata.RouteOrder => Order;
+
+ ///
+ string? IRouteNameMetadata.RouteName => Name;
}
}
diff --git a/src/Mvc/Mvc.Core/src/StatusCodeResult.cs b/src/Mvc/Mvc.Core/src/StatusCodeResult.cs
index 2f367817bdc0..30d9d84fbf1e 100644
--- a/src/Mvc/Mvc.Core/src/StatusCodeResult.cs
+++ b/src/Mvc/Mvc.Core/src/StatusCodeResult.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -12,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc
/// Represents an that when executed will
/// produce an HTTP response with the given response status code.
///
- public class StatusCodeResult : ActionResult, IClientErrorActionResult
+ public class StatusCodeResult : ActionResult, IResult, IClientErrorActionResult
{
///
/// Initializes a new instance of the class
@@ -39,12 +41,28 @@ public override void ExecuteResult(ActionContext context)
throw new ArgumentNullException(nameof(context));
}
- var factory = context.HttpContext.RequestServices.GetRequiredService();
+ Execute(context.HttpContext);
+ }
+
+ ///
+ /// Sets the status code on the HTTP response.
+ ///
+ /// The for the current request.
+ /// A task that represents the asynchronous execute operation.
+ Task IResult.ExecuteAsync(HttpContext httpContext)
+ {
+ Execute(httpContext);
+ return Task.CompletedTask;
+ }
+
+ private void Execute(HttpContext httpContext)
+ {
+ var factory = httpContext.RequestServices.GetRequiredService();
var logger = factory.CreateLogger();
logger.HttpStatusCodeResultExecuting(StatusCode);
- context.HttpContext.Response.StatusCode = StatusCode;
+ httpContext.Response.StatusCode = StatusCode;
}
}
}
diff --git a/src/Mvc/Mvc.Core/test/ApplicationModels/ControllerActionDescriptorProviderTests.cs b/src/Mvc/Mvc.Core/test/ApplicationModels/ControllerActionDescriptorProviderTests.cs
index f7f9eba93b8a..1b4b93e2686f 100644
--- a/src/Mvc/Mvc.Core/test/ApplicationModels/ControllerActionDescriptorProviderTests.cs
+++ b/src/Mvc/Mvc.Core/test/ApplicationModels/ControllerActionDescriptorProviderTests.cs
@@ -304,7 +304,7 @@ public void GetDescriptors_ActionWithHttpMethods_AddedToEndpointMetadata()
}
[Fact]
- public void GetDescriptors_ActionWithMultipleHttpMethods_SingleHttpMethodMetadata()
+ public void GetDescriptors_ActionWithMultipleHttpMethods_LastHttpMethodMetadata()
{
// Arrange & Act
var descriptors = GetDescriptors(
@@ -329,9 +329,9 @@ Action InspectElement(string httpMethod)
var httpMethodAttribute = Assert.Single(descriptor.EndpointMetadata.OfType());
Assert.Equal(httpMethod, httpMethodAttribute.HttpMethods.Single(), ignoreCase: true);
- var httpMethodMetadata = Assert.Single(descriptor.EndpointMetadata.OfType());
- Assert.Equal(httpMethod, httpMethodMetadata.HttpMethods.Single(), ignoreCase: true);
- Assert.False(httpMethodMetadata.AcceptCorsPreflight);
+ var lastHttpMethodMetadata = descriptor.EndpointMetadata.OfType().Last();
+ Assert.Equal(httpMethod, lastHttpMethodMetadata.HttpMethods.Single(), ignoreCase: true);
+ Assert.False(lastHttpMethodMetadata.AcceptCorsPreflight);
};
}
}
diff --git a/src/Mvc/Mvc.slnf b/src/Mvc/Mvc.slnf
index 49b9606749bf..26363dc5d1db 100644
--- a/src/Mvc/Mvc.slnf
+++ b/src/Mvc/Mvc.slnf
@@ -1,87 +1,57 @@
-{
+{
"solution": {
"path": "..\\..\\AspNetCore.sln",
- "projects" : [
- "src\\Mvc\\test\\WebSites\\BasicWebSite\\BasicWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\RoutingWebSite\\Mvc.RoutingWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\RazorWebSite\\RazorWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\FormatterWebSite\\FormatterWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\ApiExplorerWebSite\\ApiExplorerWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\VersioningWebSite\\VersioningWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\TagHelpersWebSite\\TagHelpersWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\RoutingWebSite\\Mvc.RoutingWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\FilesWebSite\\FilesWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\ApplicationModelWebSite\\ApplicationModelWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\HtmlGenerationWebSite\\HtmlGenerationWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\ErrorPageMiddlewareWebSite\\ErrorPageMiddlewareWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\XmlFormattersWebSite\\XmlFormattersWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\ControllersFromServicesWebSite\\ControllersFromServicesWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\ControllersFromServicesClassLibrary\\ControllersFromServicesClassLibrary.csproj",
- "src\\Mvc\\test\\WebSites\\CorsWebSite\\CorsWebSite.csproj",
- "src\\Mvc\\samples\\MvcSandbox\\MvcSandbox.csproj",
- "src\\Mvc\\test\\WebSites\\SimpleWebSite\\SimpleWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\SecurityWebSite\\SecurityWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\RazorPagesWebSite\\RazorPagesWebSite.csproj",
- "src\\Mvc\\benchmarks\\Microsoft.AspNetCore.Mvc.Performance\\Microsoft.AspNetCore.Mvc.Performance.csproj",
- "src\\Mvc\\test\\WebSites\\RazorBuildWebSite\\RazorBuildWebSite.csproj",
- "src\\Mvc\\test\\WebSites\\RazorBuildWebSite.Views\\RazorBuildWebSite.Views.csproj",
- "src\\Mvc\\Mvc.Analyzers\\src\\Microsoft.AspNetCore.Mvc.Analyzers.csproj",
- "src\\Mvc\\Mvc.Analyzers\\test\\Mvc.Analyzers.Test.csproj",
- "src\\Mvc\\test\\WebSites\\RazorPagesClassLibrary\\RazorPagesClassLibrary.csproj",
- "src\\Mvc\\shared\\Mvc.Views.TestCommon\\Microsoft.AspNetCore.Mvc.Views.TestCommon.csproj",
- "src\\Mvc\\Mvc.Api.Analyzers\\test\\Mvc.Api.Analyzers.Test.csproj",
- "src\\Mvc\\Mvc.Api.Analyzers\\src\\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj",
- "src\\Html.Abstractions\\src\\Microsoft.AspNetCore.Html.Abstractions.csproj",
- "src\\Http\\Http\\src\\Microsoft.AspNetCore.Http.csproj",
- "src\\Middleware\\CORS\\src\\Microsoft.AspNetCore.Cors.csproj",
+ "projects": [
+ "src\\Antiforgery\\src\\Microsoft.AspNetCore.Antiforgery.csproj",
+ "src\\Components\\Authorization\\src\\Microsoft.AspNetCore.Components.Authorization.csproj",
+ "src\\Components\\Components\\src\\Microsoft.AspNetCore.Components.csproj",
+ "src\\Components\\Forms\\src\\Microsoft.AspNetCore.Components.Forms.csproj",
+ "src\\Components\\Server\\src\\Microsoft.AspNetCore.Components.Server.csproj",
+ "src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
+ "src\\DataProtection\\Abstractions\\src\\Microsoft.AspNetCore.DataProtection.Abstractions.csproj",
+ "src\\DataProtection\\Cryptography.Internal\\src\\Microsoft.AspNetCore.Cryptography.Internal.csproj",
+ "src\\DataProtection\\DataProtection\\src\\Microsoft.AspNetCore.DataProtection.csproj",
+ "src\\DataProtection\\Extensions\\src\\Microsoft.AspNetCore.DataProtection.Extensions.csproj",
+ "src\\Features\\JsonPatch\\src\\Microsoft.AspNetCore.JsonPatch.csproj",
+ "src\\FileProviders\\Embedded\\src\\Microsoft.Extensions.FileProviders.Embedded.csproj",
+ "src\\Hosting\\Abstractions\\src\\Microsoft.AspNetCore.Hosting.Abstractions.csproj",
"src\\Hosting\\Hosting\\src\\Microsoft.AspNetCore.Hosting.csproj",
- "src\\Hosting\\TestHost\\src\\Microsoft.AspNetCore.TestHost.csproj",
- "src\\Middleware\\Diagnostics\\src\\Microsoft.AspNetCore.Diagnostics.csproj",
- "src\\Hosting\\Server.IntegrationTesting\\src\\Microsoft.AspNetCore.Server.IntegrationTesting.csproj",
- "src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
- "src\\Middleware\\ResponseCaching\\src\\Microsoft.AspNetCore.ResponseCaching.csproj",
- "src\\Middleware\\StaticFiles\\src\\Microsoft.AspNetCore.StaticFiles.csproj",
- "src\\Middleware\\Session\\src\\Microsoft.AspNetCore.Session.csproj",
- "src\\Middleware\\Localization.Routing\\src\\Microsoft.AspNetCore.Localization.Routing.csproj",
- "src\\Razor\\Razor.Runtime\\src\\Microsoft.AspNetCore.Razor.Runtime.csproj",
- "src\\Security\\Authentication\\Cookies\\src\\Microsoft.AspNetCore.Authentication.Cookies.csproj",
- "src\\Servers\\IIS\\IISIntegration\\src\\Microsoft.AspNetCore.Server.IISIntegration.csproj",
- "src\\Security\\Authentication\\Core\\src\\Microsoft.AspNetCore.Authentication.csproj",
- "src\\Servers\\Kestrel\\Kestrel\\src\\Microsoft.AspNetCore.Server.Kestrel.csproj",
- "src\\Security\\CookiePolicy\\src\\Microsoft.AspNetCore.CookiePolicy.csproj",
- "src\\Security\\Authorization\\Policy\\src\\Microsoft.AspNetCore.Authorization.Policy.csproj",
- "src\\Http\\Routing\\src\\Microsoft.AspNetCore.Routing.csproj",
- "src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj",
- "src\\Security\\Authentication\\JwtBearer\\src\\Microsoft.AspNetCore.Authentication.JwtBearer.csproj",
"src\\Hosting\\Server.Abstractions\\src\\Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj",
- "src\\Hosting\\Abstractions\\src\\Microsoft.AspNetCore.Hosting.Abstractions.csproj",
- "src\\Mvc\\benchmarks\\Microsoft.AspNetCore.Mvc.Performance.Views\\Microsoft.AspNetCore.Mvc.Performance.Views.csproj",
- "src\\Features\\JsonPatch\\src\\Microsoft.AspNetCore.JsonPatch.csproj",
- "src\\Middleware\\Localization\\src\\Microsoft.AspNetCore.Localization.csproj",
- "src\\Antiforgery\\src\\Microsoft.AspNetCore.Antiforgery.csproj",
- "src\\Middleware\\Diagnostics.Abstractions\\src\\Microsoft.AspNetCore.Diagnostics.Abstractions.csproj",
- "src\\Http\\Http.Extensions\\src\\Microsoft.AspNetCore.Http.Extensions.csproj",
- "src\\Middleware\\ResponseCaching.Abstractions\\src\\Microsoft.AspNetCore.ResponseCaching.Abstractions.csproj",
+ "src\\Hosting\\Server.IntegrationTesting\\src\\Microsoft.AspNetCore.Server.IntegrationTesting.csproj",
+ "src\\Hosting\\TestHost\\src\\Microsoft.AspNetCore.TestHost.csproj",
+ "src\\Html.Abstractions\\src\\Microsoft.AspNetCore.Html.Abstractions.csproj",
+ "src\\Http\\Authentication.Abstractions\\src\\Microsoft.AspNetCore.Authentication.Abstractions.csproj",
"src\\Http\\Authentication.Core\\src\\Microsoft.AspNetCore.Authentication.Core.csproj",
"src\\Http\\Headers\\src\\Microsoft.Net.Http.Headers.csproj",
- "src\\Servers\\Kestrel\\Transport.Sockets\\src\\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj",
- "src\\Servers\\Kestrel\\Core\\src\\Microsoft.AspNetCore.Server.Kestrel.Core.csproj",
"src\\Http\\Http.Abstractions\\src\\Microsoft.AspNetCore.Http.Abstractions.csproj",
- "src\\Security\\Authorization\\Core\\src\\Microsoft.AspNetCore.Authorization.csproj",
- "src\\Http\\Authentication.Abstractions\\src\\Microsoft.AspNetCore.Authentication.Abstractions.csproj",
+ "src\\Http\\Http.Extensions\\src\\Microsoft.AspNetCore.Http.Extensions.csproj",
"src\\Http\\Http.Features\\src\\Microsoft.AspNetCore.Http.Features.csproj",
- "src\\Razor\\Razor\\src\\Microsoft.AspNetCore.Razor.csproj",
- "src\\DataProtection\\DataProtection\\src\\Microsoft.AspNetCore.DataProtection.csproj",
- "src\\Servers\\Connections.Abstractions\\src\\Microsoft.AspNetCore.Connections.Abstractions.csproj",
+ "src\\Http\\Http\\src\\Microsoft.AspNetCore.Http.csproj",
+ "src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj",
+ "src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj",
+ "src\\Http\\Routing\\samples\\MapActionSample\\MapActionSample.csproj",
+ "src\\Http\\Routing\\src\\Microsoft.AspNetCore.Routing.csproj",
+ "src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
+ "src\\JSInterop\\Microsoft.JSInterop\\src\\Microsoft.JSInterop.csproj",
+ "src\\Localization\\Abstractions\\src\\Microsoft.Extensions.Localization.Abstractions.csproj",
+ "src\\Localization\\Localization\\src\\Microsoft.Extensions.Localization.csproj",
+ "src\\Middleware\\CORS\\src\\Microsoft.AspNetCore.Cors.csproj",
+ "src\\Middleware\\Diagnostics.Abstractions\\src\\Microsoft.AspNetCore.Diagnostics.Abstractions.csproj",
+ "src\\Middleware\\Diagnostics\\src\\Microsoft.AspNetCore.Diagnostics.csproj",
"src\\Middleware\\HttpOverrides\\src\\Microsoft.AspNetCore.HttpOverrides.csproj",
- "src\\DataProtection\\Cryptography.Internal\\src\\Microsoft.AspNetCore.Cryptography.Internal.csproj",
- "src\\DataProtection\\Abstractions\\src\\Microsoft.AspNetCore.DataProtection.Abstractions.csproj",
- "src\\Mvc\\test\\WebSites\\GenericHostWebSite\\GenericHostWebSite.csproj",
- "src\\Components\\Components\\src\\Microsoft.AspNetCore.Components.csproj",
- "src\\Mvc\\Mvc\\src\\Microsoft.AspNetCore.Mvc.csproj",
- "src\\Mvc\\Mvc\\test\\Microsoft.AspNetCore.Mvc.Test.csproj",
+ "src\\Middleware\\Localization.Routing\\src\\Microsoft.AspNetCore.Localization.Routing.csproj",
+ "src\\Middleware\\Localization\\src\\Microsoft.AspNetCore.Localization.csproj",
+ "src\\Middleware\\ResponseCaching.Abstractions\\src\\Microsoft.AspNetCore.ResponseCaching.Abstractions.csproj",
+ "src\\Middleware\\ResponseCaching\\src\\Microsoft.AspNetCore.ResponseCaching.csproj",
+ "src\\Middleware\\Session\\src\\Microsoft.AspNetCore.Session.csproj",
+ "src\\Middleware\\StaticFiles\\src\\Microsoft.AspNetCore.StaticFiles.csproj",
+ "src\\Middleware\\WebSockets\\src\\Microsoft.AspNetCore.WebSockets.csproj",
"src\\Mvc\\Mvc.Abstractions\\src\\Microsoft.AspNetCore.Mvc.Abstractions.csproj",
"src\\Mvc\\Mvc.Abstractions\\test\\Microsoft.AspNetCore.Mvc.Abstractions.Test.csproj",
+ "src\\Mvc\\Mvc.Analyzers\\src\\Microsoft.AspNetCore.Mvc.Analyzers.csproj",
+ "src\\Mvc\\Mvc.Analyzers\\test\\Mvc.Analyzers.Test.csproj",
+ "src\\Mvc\\Mvc.Api.Analyzers\\src\\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj",
+ "src\\Mvc\\Mvc.Api.Analyzers\\test\\Mvc.Api.Analyzers.Test.csproj",
"src\\Mvc\\Mvc.ApiExplorer\\src\\Microsoft.AspNetCore.Mvc.ApiExplorer.csproj",
"src\\Mvc\\Mvc.ApiExplorer\\test\\Microsoft.AspNetCore.Mvc.ApiExplorer.Test.csproj",
"src\\Mvc\\Mvc.Core\\src\\Microsoft.AspNetCore.Mvc.Core.csproj",
@@ -95,44 +65,74 @@
"src\\Mvc\\Mvc.Formatters.Xml\\test\\Microsoft.AspNetCore.Mvc.Formatters.Xml.Test.csproj",
"src\\Mvc\\Mvc.Localization\\src\\Microsoft.AspNetCore.Mvc.Localization.csproj",
"src\\Mvc\\Mvc.Localization\\test\\Microsoft.AspNetCore.Mvc.Localization.Test.csproj",
- "src\\Mvc\\Mvc.Razor\\src\\Microsoft.AspNetCore.Mvc.Razor.csproj",
- "src\\Mvc\\Mvc.Razor\\test\\Microsoft.AspNetCore.Mvc.Razor.Test.csproj",
+ "src\\Mvc\\Mvc.NewtonsoftJson\\src\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.csproj",
+ "src\\Mvc\\Mvc.NewtonsoftJson\\test\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.Test.csproj",
+ "src\\Mvc\\Mvc.Razor.RuntimeCompilation\\src\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.csproj",
+ "src\\Mvc\\Mvc.Razor.RuntimeCompilation\\test\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.Test.csproj",
"src\\Mvc\\Mvc.RazorPages\\src\\Microsoft.AspNetCore.Mvc.RazorPages.csproj",
"src\\Mvc\\Mvc.RazorPages\\test\\Microsoft.AspNetCore.Mvc.RazorPages.Test.csproj",
+ "src\\Mvc\\Mvc.Razor\\src\\Microsoft.AspNetCore.Mvc.Razor.csproj",
+ "src\\Mvc\\Mvc.Razor\\test\\Microsoft.AspNetCore.Mvc.Razor.Test.csproj",
"src\\Mvc\\Mvc.TagHelpers\\src\\Microsoft.AspNetCore.Mvc.TagHelpers.csproj",
"src\\Mvc\\Mvc.TagHelpers\\test\\Microsoft.AspNetCore.Mvc.TagHelpers.Test.csproj",
+ "src\\Mvc\\Mvc.Testing.Tasks\\src\\Microsoft.AspNetCore.Mvc.Testing.Tasks.csproj",
+ "src\\Mvc\\Mvc.Testing\\src\\Microsoft.AspNetCore.Mvc.Testing.csproj",
"src\\Mvc\\Mvc.ViewFeatures\\src\\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj",
"src\\Mvc\\Mvc.ViewFeatures\\test\\Microsoft.AspNetCore.Mvc.ViewFeatures.Test.csproj",
+ "src\\Mvc\\Mvc\\src\\Microsoft.AspNetCore.Mvc.csproj",
+ "src\\Mvc\\Mvc\\test\\Microsoft.AspNetCore.Mvc.Test.csproj",
+ "src\\Mvc\\benchmarks\\Microsoft.AspNetCore.Mvc.Performance.Views\\Microsoft.AspNetCore.Mvc.Performance.Views.csproj",
+ "src\\Mvc\\benchmarks\\Microsoft.AspNetCore.Mvc.Performance\\Microsoft.AspNetCore.Mvc.Performance.csproj",
+ "src\\Mvc\\samples\\MvcSandbox\\MvcSandbox.csproj",
+ "src\\Mvc\\shared\\Mvc.Core.TestCommon\\Microsoft.AspNetCore.Mvc.Core.TestCommon.csproj",
+ "src\\Mvc\\shared\\Mvc.TestDiagnosticListener\\Microsoft.AspNetCore.Mvc.TestDiagnosticListener.csproj",
+ "src\\Mvc\\shared\\Mvc.Views.TestCommon\\Microsoft.AspNetCore.Mvc.Views.TestCommon.csproj",
"src\\Mvc\\test\\Mvc.FunctionalTests\\Microsoft.AspNetCore.Mvc.FunctionalTests.csproj",
"src\\Mvc\\test\\Mvc.IntegrationTests\\Microsoft.AspNetCore.Mvc.IntegrationTests.csproj",
- "src\\Mvc\\shared\\Mvc.TestDiagnosticListener\\Microsoft.AspNetCore.Mvc.TestDiagnosticListener.csproj",
- "src\\Mvc\\Mvc.Testing\\src\\Microsoft.AspNetCore.Mvc.Testing.csproj",
- "src\\Mvc\\Mvc.Testing.Tasks\\src\\Microsoft.AspNetCore.Mvc.Testing.Tasks.csproj",
- "src\\Mvc\\shared\\Mvc.Core.TestCommon\\Microsoft.AspNetCore.Mvc.Core.TestCommon.csproj",
- "src\\Mvc\\Mvc.NewtonsoftJson\\src\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.csproj",
- "src\\Mvc\\Mvc.NewtonsoftJson\\test\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.Test.csproj",
- "src\\Mvc\\Mvc.Razor.RuntimeCompilation\\src\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.csproj",
- "src\\Mvc\\Mvc.Razor.RuntimeCompilation\\test\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.Test.csproj",
- "src\\Components\\Server\\src\\Microsoft.AspNetCore.Components.Server.csproj",
- "src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
- "src\\Middleware\\WebSockets\\src\\Microsoft.AspNetCore.WebSockets.csproj",
- "src\\SignalR\\common\\Http.Connections\\src\\Microsoft.AspNetCore.Http.Connections.csproj",
+ "src\\Mvc\\test\\WebSites\\ApiExplorerWebSite\\ApiExplorerWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\ApplicationModelWebSite\\ApplicationModelWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\BasicWebSite\\BasicWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\ControllersFromServicesClassLibrary\\ControllersFromServicesClassLibrary.csproj",
+ "src\\Mvc\\test\\WebSites\\ControllersFromServicesWebSite\\ControllersFromServicesWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\CorsWebSite\\CorsWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\ErrorPageMiddlewareWebSite\\ErrorPageMiddlewareWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\FilesWebSite\\FilesWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\FormatterWebSite\\FormatterWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\GenericHostWebSite\\GenericHostWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\HtmlGenerationWebSite\\HtmlGenerationWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\RazorBuildWebSite.PrecompiledViews\\RazorBuildWebSite.PrecompiledViews.csproj",
+ "src\\Mvc\\test\\WebSites\\RazorBuildWebSite.Views\\RazorBuildWebSite.Views.csproj",
+ "src\\Mvc\\test\\WebSites\\RazorBuildWebSite\\RazorBuildWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\RazorPagesClassLibrary\\RazorPagesClassLibrary.csproj",
+ "src\\Mvc\\test\\WebSites\\RazorPagesWebSite\\RazorPagesWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\RazorWebSite\\RazorWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\RoutingWebSite\\Mvc.RoutingWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\SecurityWebSite\\SecurityWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\SimpleWebSite\\SimpleWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\TagHelpersWebSite\\TagHelpersWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\VersioningWebSite\\VersioningWebSite.csproj",
+ "src\\Mvc\\test\\WebSites\\XmlFormattersWebSite\\XmlFormattersWebSite.csproj",
+ "src\\Razor\\Razor.Runtime\\src\\Microsoft.AspNetCore.Razor.Runtime.csproj",
+ "src\\Razor\\Razor\\src\\Microsoft.AspNetCore.Razor.csproj",
+ "src\\Security\\Authentication\\Cookies\\src\\Microsoft.AspNetCore.Authentication.Cookies.csproj",
+ "src\\Security\\Authentication\\Core\\src\\Microsoft.AspNetCore.Authentication.csproj",
+ "src\\Security\\Authentication\\JwtBearer\\src\\Microsoft.AspNetCore.Authentication.JwtBearer.csproj",
+ "src\\Security\\Authorization\\Core\\src\\Microsoft.AspNetCore.Authorization.csproj",
+ "src\\Security\\Authorization\\Policy\\src\\Microsoft.AspNetCore.Authorization.Policy.csproj",
+ "src\\Security\\CookiePolicy\\src\\Microsoft.AspNetCore.CookiePolicy.csproj",
+ "src\\Servers\\Connections.Abstractions\\src\\Microsoft.AspNetCore.Connections.Abstractions.csproj",
+ "src\\Servers\\IIS\\IISIntegration\\src\\Microsoft.AspNetCore.Server.IISIntegration.csproj",
+ "src\\Servers\\Kestrel\\Core\\src\\Microsoft.AspNetCore.Server.Kestrel.Core.csproj",
+ "src\\Servers\\Kestrel\\Kestrel\\src\\Microsoft.AspNetCore.Server.Kestrel.csproj",
+ "src\\Servers\\Kestrel\\Transport.Sockets\\src\\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj",
"src\\SignalR\\common\\Http.Connections.Common\\src\\Microsoft.AspNetCore.Http.Connections.Common.csproj",
- "src\\SignalR\\server\\SignalR\\src\\Microsoft.AspNetCore.SignalR.csproj",
- "src\\SignalR\\common\\SignalR.Common\\src\\Microsoft.AspNetCore.SignalR.Common.csproj",
- "src\\SignalR\\server\\Core\\src\\Microsoft.AspNetCore.SignalR.Core.csproj",
+ "src\\SignalR\\common\\Http.Connections\\src\\Microsoft.AspNetCore.Http.Connections.csproj",
+ "src\\SignalR\\common\\Protocols.Json\\src\\Microsoft.AspNetCore.SignalR.Protocols.Json.csproj",
"src\\SignalR\\common\\Protocols.MessagePack\\src\\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj",
"src\\SignalR\\common\\Protocols.NewtonsoftJson\\src\\Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj",
- "src\\Mvc\\test\\WebSites\\RazorBuildWebSite.PrecompiledViews\\RazorBuildWebSite.PrecompiledViews.csproj",
- "src\\SignalR\\common\\Protocols.Json\\src\\Microsoft.AspNetCore.SignalR.Protocols.Json.csproj",
- "src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj",
- "src\\Components\\Authorization\\src\\Microsoft.AspNetCore.Components.Authorization.csproj",
- "src\\Components\\Forms\\src\\Microsoft.AspNetCore.Components.Forms.csproj",
- "src\\DataProtection\\Extensions\\src\\Microsoft.AspNetCore.DataProtection.Extensions.csproj",
- "src\\FileProviders\\Embedded\\src\\Microsoft.Extensions.FileProviders.Embedded.csproj",
- "src\\Localization\\Abstractions\\src\\Microsoft.Extensions.Localization.Abstractions.csproj",
- "src\\Localization\\Localization\\src\\Microsoft.Extensions.Localization.csproj",
- "src\\JSInterop\\Microsoft.JSInterop\\src\\Microsoft.JSInterop.csproj"
+ "src\\SignalR\\common\\SignalR.Common\\src\\Microsoft.AspNetCore.SignalR.Common.csproj",
+ "src\\SignalR\\server\\Core\\src\\Microsoft.AspNetCore.SignalR.Core.csproj",
+ "src\\SignalR\\server\\SignalR\\src\\Microsoft.AspNetCore.SignalR.csproj"
]
}
-}
+}
\ No newline at end of file