-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Add new "MapAction" overloads #30556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
using System.Reflection; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.AspNetCore.Routing.Internal; | ||
using Microsoft.AspNetCore.Routing.Patterns; | ||
|
||
namespace Microsoft.AspNetCore.Builder | ||
{ | ||
|
@@ -15,6 +16,12 @@ namespace Microsoft.AspNetCore.Builder | |
/// </summary> | ||
public static class MapActionEndpointRouteBuilderExtensions | ||
{ | ||
// Avoid creating a new array every call | ||
private static readonly string[] GetVerb = new[] { "GET" }; | ||
private static readonly string[] PostVerb = new[] { "POST" }; | ||
private static readonly string[] PutVerb = new[] { "PUT" }; | ||
private static readonly string[] DeleteVerb = new[] { "DELETE" }; | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches the pattern specified via attributes. | ||
/// </summary> | ||
|
@@ -76,5 +83,203 @@ public static MapActionEndpointConventionBuilder MapAction( | |
|
||
return new MapActionEndpointConventionBuilder(conventionBuilders); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP GET requests | ||
/// for the specified pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder MapGet( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't there already Map* extension methods on route builder? Do these not colide because of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are overloads, but they should only be used for delegates that aren't |
||
this IEndpointRouteBuilder endpoints, | ||
string pattern, | ||
Delegate action) | ||
{ | ||
return MapMethods(endpoints, pattern, GetVerb, action); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP POST requests | ||
/// for the specified pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder MapPost( | ||
this IEndpointRouteBuilder endpoints, | ||
string pattern, | ||
Delegate action) | ||
{ | ||
return MapMethods(endpoints, pattern, PostVerb, action); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP PUT requests | ||
/// for the specified pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that canaction be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder MapPut( | ||
this IEndpointRouteBuilder endpoints, | ||
string pattern, | ||
Delegate action) | ||
{ | ||
return MapMethods(endpoints, pattern, PutVerb, action); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP DELETE requests | ||
/// for the specified pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder MapDelete( | ||
this IEndpointRouteBuilder endpoints, | ||
string pattern, | ||
Delegate action) | ||
{ | ||
return MapMethods(endpoints, pattern, DeleteVerb, action); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests | ||
/// for the specified HTTP methods and pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <param name="httpMethods">HTTP methods that the endpoint will match.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder MapMethods( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this? As a user, there are alternate ways to re-use the delegate if we need to. I'm also similarly against allowing more than one HTTP attributes per MapAction delegate. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that the flexibility of delegates means that we shouldn't need to make routing metadata overly complicated. That's why I removed All that said, this is an overload that already exists for |
||
this IEndpointRouteBuilder endpoints, | ||
string pattern, | ||
IEnumerable<string> httpMethods, | ||
Delegate action) | ||
{ | ||
if (httpMethods is null) | ||
{ | ||
throw new ArgumentNullException(nameof(httpMethods)); | ||
} | ||
|
||
var displayName = $"{pattern} HTTP: {string.Join(", ", httpMethods)}"; | ||
var builder = endpoints.Map(RoutePatternFactory.Parse(pattern), action, displayName); | ||
builder.WithMetadata(new HttpMethodMetadata(httpMethods)); | ||
return builder; | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests | ||
/// for the specified pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder Map( | ||
this IEndpointRouteBuilder endpoints, | ||
string pattern, | ||
Delegate action) | ||
{ | ||
return Map(endpoints, RoutePatternFactory.Parse(pattern), action); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests | ||
/// for the specified pattern. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> | ||
/// <param name="pattern">The route pattern.</param> | ||
/// <param name="action">The delegate executed when the endpoint is matched.</param> | ||
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static MapActionEndpointConventionBuilder Map( | ||
this IEndpointRouteBuilder endpoints, | ||
RoutePattern pattern, | ||
Delegate action) | ||
{ | ||
return Map(endpoints, pattern, action, displayName: null); | ||
} | ||
|
||
private static MapActionEndpointConventionBuilder Map( | ||
this IEndpointRouteBuilder endpoints, | ||
RoutePattern pattern, | ||
Delegate action, | ||
string? displayName) | ||
{ | ||
if (endpoints is null) | ||
{ | ||
throw new ArgumentNullException(nameof(endpoints)); | ||
} | ||
|
||
if (pattern is null) | ||
{ | ||
throw new ArgumentNullException(nameof(pattern)); | ||
} | ||
|
||
if (action is null) | ||
{ | ||
throw new ArgumentNullException(nameof(action)); | ||
} | ||
|
||
const int defaultOrder = 0; | ||
|
||
var builder = new RouteEndpointBuilder( | ||
MapActionExpressionTreeBuilder.BuildRequestDelegate(action), | ||
pattern, | ||
defaultOrder) | ||
{ | ||
DisplayName = pattern.RawText ?? pattern.DebuggerToString(), | ||
}; | ||
|
||
// Add delegate attributes as metadata | ||
var attributes = action.Method.GetCustomAttributes(); | ||
string? routeName = null; | ||
int? routeOrder = null; | ||
|
||
// This can be null if the delegate is a dynamic method or compiled from an expression tree | ||
if (attributes is not null) | ||
{ | ||
foreach (var attribute in attributes) | ||
{ | ||
if (attribute is IRoutePatternMetadata patternMetadata && patternMetadata.RoutePattern is not null) | ||
{ | ||
throw new InvalidOperationException($"'{attribute.GetType()}' implements {nameof(IRoutePatternMetadata)} which is not supported by this method."); | ||
} | ||
if (attribute is IHttpMethodMetadata methodMetadata && methodMetadata.HttpMethods.Any()) | ||
{ | ||
throw new InvalidOperationException($"'{attribute.GetType()}' implements {nameof(IHttpMethodMetadata)} which is not supported by this method."); | ||
} | ||
|
||
if (attribute is IRouteNameMetadata nameMetadata && nameMetadata.RouteName is string name) | ||
{ | ||
routeName = name; | ||
} | ||
if (attribute is IRouteOrderMetadata orderMetadata && orderMetadata.RouteOrder is int order) | ||
{ | ||
routeOrder = order; | ||
} | ||
|
||
builder.Metadata.Add(attribute); | ||
} | ||
} | ||
|
||
builder.DisplayName = routeName ?? displayName ?? builder.DisplayName; | ||
builder.Order = routeOrder ?? defaultOrder; | ||
|
||
var dataSource = endpoints.DataSources.OfType<ModelEndpointDataSource>().FirstOrDefault(); | ||
if (dataSource is null) | ||
{ | ||
dataSource = new ModelEndpointDataSource(); | ||
endpoints.DataSources.Add(dataSource); | ||
} | ||
|
||
return new MapActionEndpointConventionBuilder(dataSource.AddEndpointBuilder(builder)); | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.