예제 #1
0
        /// <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 MinimalActionEndpointConventionBuilder 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(
                RequestDelegateFactory.Create(action, endpoints.ServiceProvider),
                pattern,
                defaultOrder)
            {
                DisplayName = pattern.RawText ?? pattern.DebuggerToString(),
            };

            // REVIEW: Should we add an IActionMethodMetadata with just MethodInfo on it so we are
            // explicit about the MethodInfo representing the "action" and not the RequestDelegate?

            // Add MethodInfo as metadata to assist with OpenAPI generation for the endpoint.
            builder.Metadata.Add(action.Method);

            // 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 MinimalActionEndpointConventionBuilder(dataSource.AddEndpointBuilder(builder)));
        }
        /// <summary>
        /// Adds a <see cref="RouteEndpoint"/> to the <see cref="IEndpointRouteBuilder"/> that matches HTTP requests
        /// for the specified pattern.
        /// </summary>
        /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="pattern">The route pattern.</param>
        /// <param name="displayName">The display name for the endpoint.</param>
        /// <param name="requestDelegate">The delegate executed when the endpoint is matched.</param>
        /// <param name="metadata">Metadata that is added to the endpoint.</param>
        /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
        public static IEndpointConventionBuilder Map(
            this IEndpointRouteBuilder builder,
            RoutePattern pattern,
            string displayName,
            RequestDelegate requestDelegate,
            params object[] metadata)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (pattern == null)
            {
                throw new ArgumentNullException(nameof(pattern));
            }

            if (requestDelegate == null)
            {
                throw new ArgumentNullException(nameof(requestDelegate));
            }

            const int defaultOrder = 0;

            var routeEndpointBuilder = new RouteEndpointBuilder(
                requestDelegate,
                pattern,
                defaultOrder)
            {
                DisplayName = displayName
            };

            // Add delegate attributes as metadata
            foreach (var attribute in requestDelegate.Method.GetCustomAttributes())
            {
                routeEndpointBuilder.Metadata.Add(attribute);
            }

            if (metadata != null)
            {
                foreach (var item in metadata)
                {
                    routeEndpointBuilder.Metadata.Add(item);
                }
            }

            var modelEndpointDataSource = builder.DataSources.OfType <ModelEndpointDataSource>().FirstOrDefault();

            if (modelEndpointDataSource == null)
            {
                modelEndpointDataSource = new ModelEndpointDataSource();
                builder.DataSources.Add(modelEndpointDataSource);
            }

            return(modelEndpointDataSource.AddEndpointBuilder(routeEndpointBuilder));
        }
        /// <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 MinimalActionEndpointConventionBuilder 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(
                RequestDelegateFactory.Create(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 MinimalActionEndpointConventionBuilder(dataSource.AddEndpointBuilder(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="handler">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 DelegateEndpointConventionBuilder Map(
            this IEndpointRouteBuilder endpoints,
            RoutePattern pattern,
            Delegate handler)
        {
            if (endpoints is null)
            {
                throw new ArgumentNullException(nameof(endpoints));
            }

            if (pattern is null)
            {
                throw new ArgumentNullException(nameof(pattern));
            }

            if (handler is null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            const int defaultOrder = 0;

            var routeParams = new List <string>(pattern.Parameters.Count);

            foreach (var part in pattern.Parameters)
            {
                routeParams.Add(part.Name);
            }

            var routeHandlerOptions = endpoints.ServiceProvider?.GetService <IOptions <RouteHandlerOptions> >();

            var options = new RequestDelegateFactoryOptions
            {
                ServiceProvider     = endpoints.ServiceProvider,
                RouteParameterNames = routeParams,
                ThrowOnBadRequest   = routeHandlerOptions?.Value.ThrowOnBadRequest ?? false,
            };

            var requestDelegateResult = RequestDelegateFactory.Create(handler, options);

            var builder = new RouteEndpointBuilder(
                requestDelegateResult.RequestDelegate,
                pattern,
                defaultOrder)
            {
                DisplayName = pattern.RawText ?? pattern.DebuggerToString(),
            };

            // REVIEW: Should we add an IActionMethodMetadata with just MethodInfo on it so we are
            // explicit about the MethodInfo representing the "handler" and not the RequestDelegate?

            // Add MethodInfo as metadata to assist with OpenAPI generation for the endpoint.
            builder.Metadata.Add(handler.Method);

            // Methods defined in a top-level program are generated as statics so the delegate
            // target will be null. Inline lambdas are compiler generated method so they can
            // be filtered that way.
            if (GeneratedNameParser.TryParseLocalFunctionName(handler.Method.Name, out var endpointName) ||
                !TypeHelper.IsCompilerGeneratedMethod(handler.Method))
            {
                endpointName ??= handler.Method.Name;

                builder.Metadata.Add(new EndpointNameMetadata(endpointName));
                builder.Metadata.Add(new RouteNameMetadata(endpointName));
                builder.DisplayName = $"{builder.DisplayName} => {endpointName}";
            }

            // Add delegate attributes as metadata
            var attributes = handler.Method.GetCustomAttributes();

            // Add add request delegate metadata
            foreach (var metadata in requestDelegateResult.EndpointMetadata)
            {
                builder.Metadata.Add(metadata);
            }

            // 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 DelegateEndpointConventionBuilder(dataSource.AddEndpointBuilder(builder)));
        }
예제 #5
0
        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)));
        }