private static string ExtractMetadata(EndpointMetadataCollection epMetaCollection) { var metaFiltered = epMetaCollection.Where(m => !(new[] { typeof(System.Diagnostics.DebuggerStepThroughAttribute) }.Contains(m.GetType()))) .Where(t => (!t.GetType().FullName.StartsWith("System.Runtime.CompilerServices.")) && t.GetType().GetProperties().Count() > 0) .GroupBy(m => m.GetType()).Select(group => group.First()); string metaFallback; int maxDepth = 2; using (var strWriter = new StringWriter()) { using (var jsonWriter = new Json.DepthCountingJsonTextWriter(strWriter)) { bool include() => jsonWriter.CurrentDepth <= maxDepth; var resolver = new Json.DepthLimitedContractResolver(include); var jsonSerializerSettings = new JsonSerializerSettings() { ContractResolver = resolver, ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Formatting = Formatting.Indented, Converters = new[] { new Json.ShortTypeNameJsonConverter(typeof(System.Type), typeof(System.Reflection.Module), typeof(System.Reflection.MethodInfo)) } }; var serializer = JsonSerializer.CreateDefault(jsonSerializerSettings); serializer.Serialize(jsonWriter, metaFiltered); } metaFallback = strWriter.ToString(); } return(metaFallback); }
public MatcherEndpoint( Func <RequestDelegate, RequestDelegate> invoker, string template, RouteValueDictionary defaults, RouteValueDictionary requiredValues, int order, EndpointMetadataCollection metadata, string displayName) : base(metadata, displayName) { if (invoker == null) { throw new ArgumentNullException(nameof(invoker)); } if (template == null) { throw new ArgumentNullException(nameof(template)); } Invoker = invoker; Order = order; Template = template; ParsedTemplate = TemplateParser.Parse(template); RequiredValues = requiredValues; var mergedDefaults = GetDefaults(ParsedTemplate, defaults); Defaults = mergedDefaults; }
private MatcherEndpoint CreateEndpoint( string template, object defaults = null, object requiredValues = null, int order = 0, string routeName = null, EndpointMetadataCollection metadataCollection = null) { if (metadataCollection == null) { metadataCollection = EndpointMetadataCollection.Empty; if (!string.IsNullOrEmpty(routeName)) { metadataCollection = new EndpointMetadataCollection(new[] { new RouteNameMetadata(routeName) }); } } return(new MatcherEndpoint( next => (httpContext) => Task.CompletedTask, RoutePatternFactory.Parse(template, defaults, constraints: null), new RouteValueDictionary(requiredValues), order, metadataCollection, null)); }
public async Task WriteAsync_Skip_NextWriters_WhenResponseAlreadyStarted() { // Arrange var service = CreateService( writers: new List <IProblemDetailsWriter> { new MetadataBasedWriter("FirstWriter", canWrite: false), new MetadataBasedWriter("SecondWriter"), new MetadataBasedWriter("FirstWriter"), }); var metadata = new EndpointMetadataCollection(new SampleMetadata() { ContentType = "application/problem+json" }); var stream = new MemoryStream(); var context = new DefaultHttpContext() { Response = { Body = stream, StatusCode = StatusCodes.Status400BadRequest }, }; // Act await service.WriteAsync(new() { HttpContext = context, AdditionalMetadata = metadata }); // Assert Assert.Equal("\"SecondWriter\"", Encoding.UTF8.GetString(stream.ToArray())); }
private RouteEndpoint CreateEndpoint( string template, object defaults = null, object metadataRequiredValues = null, int order = 0, string routeName = null, EndpointMetadataCollection metadataCollection = null) { if (metadataCollection == null) { var metadata = new List <object>(); if (!string.IsNullOrEmpty(routeName)) { metadata.Add(new RouteNameMetadata(routeName)); } metadataCollection = new EndpointMetadataCollection(metadata); } return(new RouteEndpoint( TestConstants.EmptyRequestDelegate, RoutePatternFactory.Parse(template, defaults, parameterPolicies: null, requiredValues: metadataRequiredValues), order, metadataCollection, null)); }
public async Task WriteAsync_Skip_WhenSuccessStatusCode(int statusCode) { // Arrange var service = CreateService( writers: new List <IProblemDetailsWriter> { new MetadataBasedWriter() }); var stream = new MemoryStream(); var context = new DefaultHttpContext() { Response = { Body = stream, StatusCode = statusCode }, }; var metadata = new EndpointMetadataCollection(new SampleMetadata() { ContentType = "application/problem+json" }); context.SetEndpoint(new Endpoint(context => Task.CompletedTask, metadata, null)); // Act await service.WriteAsync(new() { HttpContext = context }); // Assert Assert.Equal(string.Empty, Encoding.UTF8.GetString(stream.ToArray())); }
/// <summary> /// Creates a new instance of <see cref="Endpoint"/>. /// </summary> /// <param name="metadata"> /// The endpoint <see cref="EndpointMetadataCollection"/>. May be null. /// </param> /// <param name="displayName"> /// The informational display name of the endpoint. May be null. /// </param> protected Endpoint( EndpointMetadataCollection metadata, string displayName) { // All are allowed to be null Metadata = metadata ?? EndpointMetadataCollection.Empty; DisplayName = displayName; }
public void GetRequiredMetadata_ThrowsWhenMetadataNotFound() { // Arrange var metadata = new EndpointMetadataCollection(1, 2); // Act Assert.Throws <InvalidOperationException>(() => metadata.GetRequiredMetadata <string>()); }
/// <summary> /// Invokes the authorization filters for the controller action. /// </summary> /// <returns>Whether the user is authenticated or not.</returns> internal static async Task <bool> InvokeAuthorizationFiltersForRequest(this ControllerContext controllerContext, ActionContext actionContext) { ControllerActionDescriptor actionDescriptor = controllerContext.ActionDescriptor; var metadataCollection = new EndpointMetadataCollection(actionDescriptor.EndpointMetadata.Union(new[] { actionDescriptor })); IReadOnlyList <IAuthorizeData> authorizeData = metadataCollection.GetOrderedMetadata <IAuthorizeData>(); IAuthorizationPolicyProvider policyProvider = controllerContext.HttpContext.RequestServices .GetRequiredService <IAuthorizationPolicyProvider>(); AuthorizationPolicy?policy = await AuthorizationPolicy.CombineAsync(policyProvider, authorizeData); if (policy is not null) { IPolicyEvaluator policyEvaluator = controllerContext.HttpContext.RequestServices.GetRequiredService <IPolicyEvaluator>(); AuthenticateResult authenticateResult = await policyEvaluator.AuthenticateAsync(policy, controllerContext.HttpContext); if (!authenticateResult.Succeeded) { return(false); } // TODO this is super hacky, but we rely on the FeatureAuthorizeHandler can still handle endpoints // (The way before .NET 5). The .NET 5 way would need to use han http context, for the "inner" request // with the nested controller var resource = new Endpoint(null, metadataCollection, null); PolicyAuthorizationResult authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, controllerContext.HttpContext, resource); if (!authorizeResult.Succeeded) { return(false); } } IList <FilterDescriptor> filters = actionDescriptor.FilterDescriptors; var filterGrouping = new FilterGrouping(filters, controllerContext.HttpContext.RequestServices); // because the continuation gets built from the inside out we need to reverse the filter list // so that least specific filters (Global) get run first and the most specific filters (Action) get run last. var authorizationFilters = filterGrouping.AuthorizationFilters.Reverse().ToList(); var asyncAuthorizationFilters = filterGrouping.AsyncAuthorizationFilters.Reverse().ToList(); if (authorizationFilters.Count == 0 && asyncAuthorizationFilters.Count == 0) { return(true); } // if the authorization filter returns a result, it means it failed to authorize var authorizationFilterContext = new AuthorizationFilterContext(actionContext, filters.Select(x => x.Filter).ToArray()); return(await ExecuteAuthorizationFiltersAsync(authorizationFilterContext, authorizationFilters, asyncAuthorizationFilters)); }
public void GetRequiredMetadata_CanReturnMetadata() { // Arrange var metadata = new EndpointMetadataCollection(1, "2"); // Act var requiredMetadata = metadata.GetRequiredMetadata <string>(); Assert.Equal("2", requiredMetadata); }
/// <summary> /// Creates a new instance of the <see cref="RouteHandlerContext"/>. /// </summary> /// <param name="methodInfo">The <see cref="MethodInfo"/> associated with the route handler of the current request.</param> /// <param name="endpointMetadata">The <see cref="EndpointMetadataCollection"/> associated with the endpoint the filter is targeting.</param> /// <param name="applicationServices">The <see cref="IServiceProvider"/> instance used to access the application services.</param> public RouteHandlerContext(MethodInfo methodInfo, EndpointMetadataCollection endpointMetadata, IServiceProvider applicationServices) { ArgumentNullException.ThrowIfNull(methodInfo); ArgumentNullException.ThrowIfNull(endpointMetadata); ArgumentNullException.ThrowIfNull(applicationServices); MethodInfo = methodInfo; EndpointMetadata = endpointMetadata; ApplicationServices = applicationServices; }
public void GetOrderedMetadata_CanReturnEmptyCollection() { // Arrange var metadata = new EndpointMetadataCollection(1, 2, 3); // Act var ordered = metadata.GetOrderedMetadata <string>(); Assert.Same(Array.Empty <string>(), ordered); }
/// <summary> /// Creates a new instance of <see cref="Endpoint"/>. /// </summary> /// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param> /// <param name="metadata"> /// The endpoint <see cref="EndpointMetadataCollection"/>. May be null. /// </param> /// <param name="displayName"> /// The informational display name of the endpoint. May be null. /// </param> public Endpoint( RequestDelegate requestDelegate, EndpointMetadataCollection metadata, string displayName) { // All are allowed to be null RequestDelegate = requestDelegate; Metadata = metadata ?? EndpointMetadataCollection.Empty; DisplayName = displayName; }
private MatcherEndpoint CreateEndpoint(ActionDescriptor action, string template, int order, object source) { RequestDelegate invokerDelegate = (context) => { var values = context.Features.Get <IEndpointFeature>().Values; var routeData = new RouteData(); foreach (var kvp in values) { if (kvp.Value != null) { routeData.Values.Add(kvp.Key, kvp.Value); } } var actionContext = new ActionContext(context, routeData, action); var invoker = _invokerFactory.CreateInvoker(actionContext); return(invoker.InvokeAsync()); }; var metadata = new List <object>(); // REVIEW: Used for debugging. Consider removing before release metadata.Add(source); metadata.Add(action); // Add filter descriptors to endpoint metadata if (action.FilterDescriptors != null && action.FilterDescriptors.Count > 0) { metadata.AddRange(action.FilterDescriptors.OrderBy(f => f, FilterDescriptorOrderComparer.Comparer).Select(f => f.Filter)); } if (action.ActionConstraints != null && action.ActionConstraints.Count > 0) { foreach (var actionConstraint in action.ActionConstraints) { if (actionConstraint is HttpMethodActionConstraint httpMethodActionConstraint) { metadata.Add(new HttpMethodEndpointConstraint(httpMethodActionConstraint.HttpMethods)); } } } var metadataCollection = new EndpointMetadataCollection(metadata); var endpoint = new MatcherEndpoint( next => invokerDelegate, template, action.RouteValues, order, metadataCollection, action.DisplayName, address: null); return(endpoint); }
private void InitializeEndpoints() { // note: this code has haxxx. This will only work in some constrained scenarios foreach (var action in _actions.ActionDescriptors.Items) { if (action.AttributeRouteInfo == null) { // Action does not have an attribute route continue; } RequestDelegate invokerDelegate = (context) => { var values = context.Features.Get <IEndpointFeature>().Values; var routeData = new RouteData(); foreach (var kvp in values) { routeData.Values.Add(kvp.Key, kvp.Value); } var actionContext = new ActionContext(context, routeData, action); var invoker = _invokerFactory.CreateInvoker(actionContext); return(invoker.InvokeAsync()); }; var metadata = new List <object>(); // Add filter descriptors to endpoint metadata metadata.AddRange(action.FilterDescriptors.OrderBy(f => f, FilterDescriptorOrderComparer.Comparer).Select(f => f.Filter)); if (action.ActionConstraints != null && action.ActionConstraints.Count > 0) { foreach (var actionConstraint in action.ActionConstraints) { if (actionConstraint is HttpMethodActionConstraint httpMethodActionConstraint) { metadata.Add(new HttpMethodEndpointConstraint(httpMethodActionConstraint.HttpMethods)); } } } var metadataCollection = new EndpointMetadataCollection(metadata); _endpoints.Add(new MatcherEndpoint( next => invokerDelegate, action.AttributeRouteInfo.Template, action.RouteValues, action.AttributeRouteInfo.Order, metadataCollection, action.DisplayName, new Address(action.AttributeRouteInfo.Name))); } }
// TODO wrap these into configuration via json or something better public static IEndpointDataSourceBuilder AddProxyEndpoint(this IEndpointDataSourceBuilder builder, RoutePattern routePattern, RouteValueDictionary requiredValues, int order, EndpointMetadataCollection metadata, string displayName, Uri matchUri) { builder.Endpoints.Add(new ProxyEndpoint(routePattern, requiredValues, order, metadata, displayName, matchUri)); return(builder); }
private static EndpointMetadataCollection BuildEndpointMetadata( ActionDescriptor action, string routeName, object source, bool suppressLinkGeneration) { var metadata = new List <object>(); // REVIEW: Used for debugging. Consider removing before release metadata.Add(source); metadata.Add(action); if (!string.IsNullOrEmpty(routeName)) { metadata.Add(new RouteNameMetadata(routeName)); } // Add filter descriptors to endpoint metadata if (action.FilterDescriptors != null && action.FilterDescriptors.Count > 0) { metadata.AddRange(action.FilterDescriptors.OrderBy(f => f, FilterDescriptorOrderComparer.Comparer) .Select(f => f.Filter)); } if (action.ActionConstraints != null && action.ActionConstraints.Count > 0) { // REVIEW: What is the best way to pick up endpoint constraints of an ActionDescriptor? // Currently they need to implement IActionConstraintMetadata foreach (var actionConstraint in action.ActionConstraints) { if (actionConstraint is HttpMethodActionConstraint httpMethodActionConstraint) { metadata.Add(new HttpMethodEndpointConstraint(httpMethodActionConstraint.HttpMethods)); } else if (actionConstraint is IEndpointConstraintMetadata) { // The constraint might have been added earlier, e.g. it is also a filter descriptor if (!metadata.Contains(actionConstraint)) { metadata.Add(actionConstraint); } } } } if (suppressLinkGeneration) { metadata.Add(new SuppressLinkGenerationMetadata()); } var metadataCollection = new EndpointMetadataCollection(metadata); return(metadataCollection); }
public void GetOrderedMetadata_CanReturnNonEmptyCollection() { // Arrange var metadata = new EndpointMetadataCollection("1", "2"); // Act var ordered1 = metadata.GetOrderedMetadata <string>(); var ordered2 = metadata.GetOrderedMetadata <string>(); Assert.Same(ordered1, ordered2); Assert.Equal(new string[] { "1", "2" }, ordered1); }
private MatcherEndpoint CreateEndpoint(params IEndpointConstraint[] constraints) { var endpointMetadata = new EndpointMetadataCollection(constraints); return(new MatcherEndpoint( (r) => null, RoutePatternFactory.Parse("/"), new RouteValueDictionary(), 0, endpointMetadata, "")); }
private MatcherEndpoint CreateEndpoint(params IEndpointConstraint[] constraints) { EndpointMetadataCollection endpointMetadata = new EndpointMetadataCollection(constraints); return(new MatcherEndpoint( (r) => null, "", new RouteValueDictionary(), new RouteValueDictionary(), 0, endpointMetadata, "")); }
public void Constructor_ParamsArray_ContainsValues() { // Arrange & Act var metadata = new EndpointMetadataCollection(1, 2, 3); // Assert Assert.Equal(3, metadata.Count); Assert.Collection(metadata, value => Assert.Equal(1, value), value => Assert.Equal(2, value), value => Assert.Equal(3, value)); }
public RouteEndpoint BuildEndpoint(IContainer container) { var handler = CreateHandler(container); var pattern = Route.BuildRoutePattern(); // TODO -- do more to pick up attributes here like [Authorize] and [AllowAnonymous] var metadata = new EndpointMetadataCollection(new HttpMethodMetadata(new string[] { Route.HttpMethod })); var endpoint = new RouteEndpoint(c => handler.Handle(c), pattern, Route.Order, metadata, Route.Description); return(endpoint); }
private MatcherEndpoint CreateEndpoint(string routeName, string template, object defaults, int order) { var metadata = EndpointMetadataCollection.Empty; if (!string.IsNullOrEmpty(routeName)) { metadata = new EndpointMetadataCollection(new[] { new RouteNameMetadata(routeName) }); } return(new MatcherEndpoint( next => (httpContext) => Task.CompletedTask, RoutePatternFactory.Parse(template, defaults, constraints: null), new RouteValueDictionary(), order, metadata, "DisplayName")); }
private static OpenApiOperation?GetOperationForEndpoint(RouteEndpointBuilder routeEndpointBuilder) { var pattern = routeEndpointBuilder.RoutePattern; var metadata = new EndpointMetadataCollection(routeEndpointBuilder.Metadata); var methodInfo = metadata.OfType <MethodInfo>().SingleOrDefault(); var serviceProvider = routeEndpointBuilder.ServiceProvider; if (methodInfo == null || serviceProvider == null) { return(null); } var hostEnvironment = serviceProvider.GetService <IHostEnvironment>(); var serviceProviderIsService = serviceProvider.GetService <IServiceProviderIsService>(); var generator = new OpenApiGenerator(hostEnvironment, serviceProviderIsService); return(generator.GetOpenApiOperation(methodInfo, metadata, pattern)); }
public void Constructor_Enumeration_ContainsValues() { // Arrange & Act var metadata = new EndpointMetadataCollection(new List <object> { 1, 2, 3, }); // Assert Assert.Equal(3, metadata.Count); Assert.Collection(metadata, value => Assert.Equal(1, value), value => Assert.Equal(2, value), value => Assert.Equal(3, value)); }
public ProxyEndpoint( RoutePattern routePattern, RouteValueDictionary requiredValues, int order, EndpointMetadataCollection metadata, string displayName, Uri matchUri) : base(metadata, displayName) { Invoker = (next) => (httpContext) => { return(httpContext.ProxyRequest(matchUri)); }; RoutePattern = routePattern ?? throw new ArgumentNullException(nameof(routePattern)); RequiredValues = requiredValues; Order = order; MatchUri = matchUri; }
private RouteEndpoint CreateEndpoint( string template, object defaults = null, object requiredValues = null, int order = 0, string routeName = null, EndpointMetadataCollection metadataCollection = null) { if (metadataCollection == null) { metadataCollection = new EndpointMetadataCollection( new RouteValuesAddressMetadata(routeName, new RouteValueDictionary(requiredValues))); } return(new RouteEndpoint( (httpContext) => Task.CompletedTask, RoutePatternFactory.Parse(template, defaults, parameterPolicies: null), order, metadataCollection, null)); }
/// <summary> /// Initializes a new instance of the <see cref="RouteEndpoint"/> class. /// </summary> /// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param> /// <param name="routePattern">The <see cref="RoutePattern"/> to use in URL matching.</param> /// <param name="order">The order assigned to the endpoint.</param> /// <param name="metadata"> /// The <see cref="EndpointMetadataCollection"/> or metadata associated with the endpoint. /// </param> /// <param name="displayName">The informational display name of the endpoint.</param> public RouteEndpoint( RequestDelegate requestDelegate, RoutePattern routePattern, int order, EndpointMetadataCollection metadata, string displayName) : base(requestDelegate, metadata, displayName) { if (requestDelegate == null) { throw new ArgumentNullException(nameof(requestDelegate)); } if (routePattern == null) { throw new ArgumentNullException(nameof(routePattern)); } RoutePattern = routePattern; Order = order; }
/// <summary> /// Initializes a new instance of the <see cref="MatcherEndpoint"/> class. /// </summary> /// <param name="invoker">The delegate to invoke to create a <see cref="RequestDelegate"/>.</param> /// <param name="routePattern">The <see cref="RoutePattern"/> to use in URL matching.</param> /// <param name="order">The order assigned to the endpoint.</param> /// <param name="metadata"> /// The <see cref="EndpointMetadataCollection"/> or metadata associated with the endpoint. /// </param> /// <param name="displayName">The informational display name of the endpoint.</param> public MatcherEndpoint( Func <RequestDelegate, RequestDelegate> invoker, RoutePattern routePattern, int order, EndpointMetadataCollection metadata, string displayName) : base(metadata, displayName) { if (invoker == null) { throw new ArgumentNullException(nameof(invoker)); } if (routePattern == null) { throw new ArgumentNullException(nameof(routePattern)); } Invoker = invoker; RoutePattern = routePattern; Order = order; }
public void Setup() { var seeds = new Type[] { typeof(Metadata1), typeof(Metadata2), typeof(Metadata3), typeof(Metadata4), typeof(Metadata5), typeof(Metadata6), typeof(Metadata7), typeof(Metadata8), typeof(Metadata9), }; _items = new object[Count]; for (var i = 0; i < _items.Length; i++) { _items[i] = seeds[i % seeds.Length]; } _collection = new EndpointMetadataCollection(_items); }