예제 #1
0
        public void Apply_EnrichesOperationMetadata_IfMinimalActionDecoratedWithSwaggerOperationAttribute()
        {
            var operationAttribute = new SwaggerOperationAttribute("Summary for ActionWithSwaggerOperationAttribute")
            {
                Description = "Description for ActionWithSwaggerOperationAttribute",
                OperationId = "actionWithSwaggerOperationAttribute",
                Tags        = new[] { "foobar" }
            };

            var action = RequestDelegateFactory.Create((string parameter) => "{}");

            var operation  = new OpenApiOperation();
            var methodInfo = action.RequestDelegate.Method;

            var apiDescription = new ApiDescription()
            {
                ActionDescriptor = new ActionDescriptor()
                {
                    EndpointMetadata = new[] { operationAttribute }
                }
            };

            var filterContext = new OperationFilterContext(
                apiDescription: apiDescription,
                schemaRegistry: null,
                schemaRepository: null,
                methodInfo: methodInfo);

            Subject().Apply(operation, filterContext);

            Assert.Equal("Summary for ActionWithSwaggerOperationAttribute", operation.Summary);
            Assert.Equal("Description for ActionWithSwaggerOperationAttribute", operation.Description);
            Assert.Equal("actionWithSwaggerOperationAttribute", operation.OperationId);
            Assert.Equal(new[] { "foobar" }, operation.Tags.Cast <OpenApiTag>().Select(t => t.Name));
        }
예제 #2
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)));
        }
예제 #3
0
        public async Task RequestDelegateInvokesAction(Delegate @delegate)
        {
            var httpContext = new DefaultHttpContext();

            var requestDelegate = RequestDelegateFactory.Create(@delegate);

            await requestDelegate(httpContext);

            Assert.True(httpContext.Items["invoked"] as bool?);
        }
예제 #4
0
        public async Task RequestDelegatePopulatesFromRouteOptionalParameter()
        {
            var httpContext = new DefaultHttpContext();

            var requestDelegate = RequestDelegateFactory.Create((Action <HttpContext, int>)TestAction);

            await requestDelegate(httpContext);

            Assert.Equal(42, httpContext.Items["input"]);
        }
        public async Task RequestDelegatePopulatesFromRouteOptionalParameter(Delegate @delegate)
        {
            var httpContext = new DefaultHttpContext();

            var requestDelegate = RequestDelegateFactory.Create(@delegate);

            await requestDelegate(httpContext);

            Assert.Equal(42, httpContext.Items["input"] as int?);
        }
예제 #6
0
        public async Task RequestDelegatePopulatesFromOptionalStringParameter()
        {
            var httpContext = new DefaultHttpContext();

            var requestDelegate = RequestDelegateFactory.Create((Action <HttpContext, string>)TestOptionalString);

            await requestDelegate(httpContext);

            Assert.Equal("default", httpContext.Items["input"]);
        }
        /// <summary>
        /// Adds <see cref="ReloadPipelineMiddleware"/> to the middleware pipeline, with a method to obtain a change token used to be notified that the pipleine should be reloaded.
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="changeTokenFactory">Function that is used to obtain an <see cref="IChangeToken"/></param> that will signal when the pipeline should be reloaded.
        /// <param name="configure"></param>
        /// <param name="isTerminal"></param>
        /// <returns></returns>
        public static IApplicationBuilder AddReloadablePipelineMiddleware(this IApplicationBuilder builder,
                                                                          Func <IChangeToken> changeTokenFactory,
                                                                          Action <IApplicationBuilder> configure,
                                                                          bool isTerminal)
        {
            var factory = new RequestDelegateFactory(changeTokenFactory, configure);

            builder.UseMiddleware <ReloadPipelineMiddleware>(builder, factory, isTerminal);
            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 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)));
        }
예제 #9
0
        public async Task RequestDelegatePopulatesFromRouteOptionalParameterBasedOnParameterName()
        {
            const string paramName          = "value";
            const int    originalRouteParam = 47;

            var httpContext = new DefaultHttpContext();

            httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo);

            var requestDelegate = RequestDelegateFactory.Create((Action <HttpContext, int>)TestAction);

            await requestDelegate(httpContext);

            Assert.Equal(47, httpContext.Items["input"]);
        }
        public async Task RequestDelegatePopulatesFromRouteParameterBasedOnParameterName(Delegate @delegate)
        {
            const string paramName          = "value";
            const int    originalRouteParam = 42;

            var httpContext = new DefaultHttpContext();

            httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo);

            var requestDelegate = RequestDelegateFactory.Create(@delegate);

            await requestDelegate(httpContext);

            Assert.Equal(originalRouteParam, httpContext.Items["input"] as int?);
        }
        /// <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)));
        }