/// <summary> /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches the pattern specified via attributes. /// </summary> /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> /// <param name="action">The delegate executed when the endpoint is matched.</param> /// <returns>An <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns> 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 <IRoutePatternMetadata>(); var conventionBuilders = new List <IEndpointConventionBuilder>(); 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)); }
/// <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) { 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(); // 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) { builder.Metadata.Add(attribute); } } var dataSource = endpoints.DataSources.OfType <ModelEndpointDataSource>().FirstOrDefault(); if (dataSource is null) { dataSource = new ModelEndpointDataSource(); endpoints.DataSources.Add(dataSource); } return(new MapActionEndpointConventionBuilder(dataSource.AddEndpointBuilder(builder))); }
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))); }