public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate() { // Arrange var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), }; var scores = new int[] { 0, 0, 1 }; var candidateSet = CreateCandidateSet(endpoints, scores); candidateSet.SetValidity(0, false); candidateSet.SetValidity(1, true); candidateSet.SetValidity(2, true); var httpContext = CreateContext(); var selector = CreateSelector(); // Act await selector.SelectAsync(httpContext, candidateSet); // Assert Assert.Same(endpoints[1], httpContext.GetEndpoint()); }
private void AddRequiredLiteralValue(RouteEndpoint endpoint, List <DfaNode> nextParents, DfaNode parent, RoutePatternParameterPart parameterPart, object requiredValue) { if (endpoint.RoutePattern.ParameterPolicies.TryGetValue(parameterPart.Name, out var parameterPolicyReferences)) { for (var k = 0; k < parameterPolicyReferences.Count; k++) { var reference = parameterPolicyReferences[k]; var parameterPolicy = _parameterPolicyFactory.Create(parameterPart, reference); if (parameterPolicy is IOutboundParameterTransformer parameterTransformer) { requiredValue = parameterTransformer.TransformOutbound(requiredValue); break; } } } var literalValue = requiredValue?.ToString() ?? throw new InvalidOperationException($"Required value for literal '{parameterPart.Name}' must evaluate to a non-null string."); AddLiteralNode(_includeLabel, nextParents, parent, literalValue); }
public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate() { // Arrange var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), }; var scores = new int[] { 0, 0, 1 }; var candidateSet = CreateCandidateSet(endpoints, scores); candidateSet[0].IsValidCandidate = false; candidateSet[1].IsValidCandidate = true; candidateSet[2].IsValidCandidate = true; var(httpContext, feature) = CreateContext(); var selector = CreateSelector(); // Act await selector.SelectAsync(httpContext, feature, candidateSet); // Assert Assert.Same(endpoints[1], feature.Endpoint); }
private bool MatchesEndpoint(string absPath) { // Borrowed and modified from https://stackoverflow.com/a/59550580 // Return a collection of Microsoft.AspNetCore.Http.Endpoint instances. IEnumerable <RouteEndpoint> routeEndpoints = _endpointDataSource?.Endpoints .OfType <RouteEndpoint>() .Where(x => { // We don't want to include dynamic endpoints in this check since we would have no idea if that // matches since they will probably match everything. bool isDynamic = x.Metadata.OfType <IDynamicEndpointMetadata>().Any(x => x.IsDynamic); if (isDynamic) { return(false); } // filter out matched endpoints that are suppressed var isSuppressed = x.Metadata.OfType <ISuppressMatchingMetadata>().FirstOrDefault()?.SuppressMatching == true; if (isSuppressed) { return(false); } return(true); }); var routeValues = new RouteValueDictionary(); // To get the matchedEndpoint of the provide url RouteEndpoint matchedEndpoint = routeEndpoints? .Where(e => e.RoutePattern.RawText != null) .Where(e => new TemplateMatcher( TemplateParser.Parse(e.RoutePattern.RawText), new RouteValueDictionary()) .TryMatch(absPath, routeValues)) .OrderBy(c => c.Order) .FirstOrDefault(); return(matchedEndpoint != null); }
public async Task Match_Regression_1867_DefaultBehavior(string path, int endpointIndex) { var endpoints = new RouteEndpoint[] { EndpointFactory.CreateRouteEndpoint( "{firstName}/{lastName}", order: 0, defaults: new { controller = "TestRoute", action = "Index", }), EndpointFactory.CreateRouteEndpoint( "middleware/{**_}", order: 0), }; var expected = endpointIndex switch { -1 => null, _ => endpoints[endpointIndex], }; var matcher = CreateMatcher(useCorrectCatchAllBehavior: default, endpoints);
public void IsPartOfRouteTemplate_ReturnsCorrect_ForGivenPart(string part, bool expect) { // Arrange RouteEndpoint endpoint = new RouteEndpoint( c => Task.CompletedTask, RoutePatternFactory.Parse("odata/customers/{key}/Name"), 0, EndpointMetadataCollection.Empty, "test"); ODataTemplateTranslateContext translateContext = new ODataTemplateTranslateContext { Endpoint = endpoint }; // Act bool actual = translateContext.IsPartOfRouteTemplate(part); // Assert Assert.Equal(expect, actual); }
public void Matcher_Ignores_SuppressedEndpoint() { // Arrange var dataSource = new DynamicEndpointDataSource(); var endpoint = new RouteEndpoint( TestConstants.EmptyRequestDelegate, RoutePatternFactory.Parse("/"), 0, new EndpointMetadataCollection(new SuppressMatchingMetadata()), "test"); dataSource.AddEndpoint(endpoint); // Act var matcher = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create); // Assert var inner = Assert.IsType <TestMatcher>(matcher.CurrentMatcher); Assert.Empty(inner.Endpoints); }
public void TryTranslateKeySegmentTemplate_ThrowsODataException_ForInvalidKey() { // Arrange EdmModel model = new EdmModel(); EdmEntityType customerType = new EdmEntityType("NS", "Customer"); EdmStructuralProperty idProperty = customerType.AddStructuralProperty("customerId", EdmPrimitiveTypeKind.Int32); customerType.AddKeys(idProperty); model.AddElement(customerType); EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); EdmEntitySet customers = container.AddEntitySet("Customers", customerType); model.AddElement(container); RouteValueDictionary routeValueDictionary = new RouteValueDictionary(new { key = "abc12" }); IDictionary <string, string> keys = new Dictionary <string, string> { { "customerId", "{key}" } }; KeySegmentTemplate template = new KeySegmentTemplate(keys, customerType, customers); RouteEndpoint endpoint = new RouteEndpoint( c => Task.CompletedTask, RoutePatternFactory.Parse("odata/customers/{key}/Name"), 0, EndpointMetadataCollection.Empty, "test"); ODataTemplateTranslateContext context = new ODataTemplateTranslateContext { RouteValues = routeValueDictionary, Model = model, Endpoint = endpoint }; // Act Action test = () => template.TryTranslate(context); // Assert ExceptionAssert.Throws <ODataException>(test, "The key value (abc12) from request is not valid. The key value should be format of type 'Edm.Int32'."); }
private void MapControllerActions(Type type) { foreach (MethodInfo method in type.GetMethods()) { if (type.IsAbstract || type.IsNotPublic) { continue; } if (method.ReturnType.Equals(typeof(IActionResult))) { var controller = type.Name.Replace("Controller", string.Empty).ToLower(); var action = method.Name.ToLower(); var uri = $"{controller}/{action}"; var requestDelegate = _controllerFactory.CreateRequestDelegate(type, method); var endpoint = new RouteEndpoint(requestDelegate, uri, null, $"/{uri}"); _endpoints.Add(uri, endpoint); } } }
public IEnumerable <Endpoint> FindEndpoints(RouteValuesAddress address) { if (address.AmbientValues == null || address.ExplicitValues == null) { return(Enumerable.Empty <Endpoint>()); } var homeRoute = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult().HomeRoute; if (Match(homeRoute, address.ExplicitValues)) { var routeValues = new RouteValueDictionary(address.ExplicitValues); if (address.ExplicitValues.Count > homeRoute.Count) { foreach (var entry in address.ExplicitValues) { if (!homeRoute.ContainsKey(entry.Key)) { routeValues.Remove(entry.Key); } } } var endpoint = new RouteEndpoint ( c => null, RoutePatternFactory.Parse(String.Empty, routeValues, null), 0, null, null ); return(new[] { endpoint }); } return(Enumerable.Empty <Endpoint>()); }
public void Setup() { Endpoints = new RouteEndpoint[10]; Endpoints[0] = CreateEndpoint("/product", "GET"); Endpoints[1] = CreateEndpoint("/product/{id}", "GET"); Endpoints[2] = CreateEndpoint("/account", "GET"); Endpoints[3] = CreateEndpoint("/account/{id}"); Endpoints[4] = CreateEndpoint("/account/{id}", "POST"); Endpoints[5] = CreateEndpoint("/account/{id}", "UPDATE"); Endpoints[6] = CreateEndpoint("/v2/account", "GET"); Endpoints[7] = CreateEndpoint("/v2/account/{id}"); Endpoints[8] = CreateEndpoint("/v2/account/{id}", "POST"); Endpoints[9] = CreateEndpoint("/v2/account/{id}", "UPDATE"); // Define an unordered mixture of policies that implement INodeBuilderPolicy, // IEndpointComparerPolicy and/or IEndpointSelectorPolicy _policies = new List <MatcherPolicy>() { CreateNodeBuilderPolicy(4), CreateUberPolicy(2), CreateNodeBuilderPolicy(3), CreateEndpointComparerPolicy(5), CreateNodeBuilderPolicy(1), CreateEndpointSelectorPolicy(9), CreateEndpointComparerPolicy(7), CreateNodeBuilderPolicy(6), CreateEndpointSelectorPolicy(10), CreateUberPolicy(12), CreateEndpointComparerPolicy(11) }; _loggerFactory = NullLoggerFactory.Instance; _selector = new DefaultEndpointSelector(); _parameterPolicyFactory = new DefaultParameterPolicyFactory(Options.Create(new RouteOptions()), new TestServiceProvider()); _services = CreateServices(); }
public void Matcher_Reinitializes_WhenDataSourceChanges() { // Arrange var dataSource = new DynamicEndpointDataSource(); var matcher = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create); var endpoint = new RouteEndpoint( TestConstants.EmptyRequestDelegate, RoutePatternFactory.Parse("a/b/c"), 0, EndpointMetadataCollection.Empty, "test"); // Act dataSource.AddEndpoint(endpoint); // Assert var inner = Assert.IsType <TestMatcher>(matcher.CurrentMatcher); Assert.Collection( inner.Endpoints, e => Assert.Same(endpoint, e)); }
public static ApiDescription?TryCreateApiDescription(RouteEndpoint endpoint) { var metadata = endpoint.Metadata.GetMetadata <GrpcMethodMetadata>(); if (metadata == null) { return(null); } var marker = FindServiceModelGrpcMarker(endpoint.Metadata); if (marker == null) { return(null); } var operation = new OperationDescription( metadata.Method.ServiceName, metadata.Method.Name, new MessageAssembler(marker.ContractMethodDefinition)); return(CreateApiDescription(endpoint, metadata, operation)); }
public async Task SelectAsync_MultipleValidCandidatesInGroup_ReportsAmbiguity() { // Arrange var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), }; var scores = new int[] { 0, 1, 1 }; var candidateSet = CreateCandidateSet(endpoints, scores); candidateSet.SetValidity(0, false); candidateSet.SetValidity(1, true); candidateSet.SetValidity(2, true); var httpContext = CreateContext(); var selector = CreateSelector(); // Act var ex = await Assert.ThrowsAsync <AmbiguousMatchException>(() => selector.SelectAsync(httpContext, candidateSet)); // Assert Assert.Equal( @"The request matched multiple endpoints. Matches: " + Environment.NewLine + Environment.NewLine + "test: /test2" + Environment.NewLine + "test: /test3", ex.Message); Assert.Null(httpContext.GetEndpoint()); }
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, auth_handler_requirement requirement) { //if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth && // c.Issuer == "http://contoso.com")) //{ //TODO: Use the following if targeting a version of //.NET Framework older than 4.6: // return Task.FromResult(0); // return Task.CompletedTask; RouteEndpoint endpoint = (RouteEndpoint)context.Resource; var apistring = endpoint.RoutePattern.RawText; //context.Succeed(requirement); var a = requirement._iAuth.GetRights(int.Parse(context.User.Claims.First(i => i.Type == "userID").Value)).Result; if (a.Where(x => x.api == apistring).Count() > 0) { context.Succeed(requirement); // Basically check if the user has that specific right. } return(Task.CompletedTask); }
/// <summary> /// Checks whether the endpoint is matched the relative uri specified int the request info. /// </summary> /// <param name="routeEndpoint">The route endpoint.</param> /// <param name="requestInfo">The request information.</param> /// <param name="routeValueDictionary">The route value dictionary.</param> /// <returns> /// Whether the endpoint matches the request info relative uri. /// </returns> private static EndpointMatchResult EndpointMatches(RouteEndpoint routeEndpoint, RequestInfo requestInfo, out RouteValueDictionary routeValueDictionary) { if (!_templateMatcherCache.TryGetValue(routeEndpoint.RoutePattern.RawText, out TemplateMatcher templateMatcher)) { RouteTemplate template = TemplateParser.Parse(routeEndpoint.RoutePattern.RawText); templateMatcher = new TemplateMatcher(template, GetDefaultRouteValues(template)); _templateMatcherCache.TryAdd(routeEndpoint.RoutePattern.RawText, templateMatcher); } routeValueDictionary = new RouteValueDictionary(); if (templateMatcher.TryMatch(new PathString(requestInfo.RelativeUri), routeValueDictionary)) { // Check if the HTTP method matches string requestHttpMethod = requestInfo.Method.ToLower(); HttpMethodMetadata httpMethodMetadata = routeEndpoint.Metadata.GetMetadata <HttpMethodMetadata>(); if (httpMethodMetadata == null && requestHttpMethod != HttpMethod.Get.ToString().ToLower()) { // Assume get if no metadata is found return(EndpointMatchResult.NoMatch); } if (!httpMethodMetadata.HttpMethods.Any(httpMethod => httpMethod.ToLower() == requestHttpMethod)) { // Http method is not matching return(EndpointMatchResult.NoMatch); } // Check if this endpoint is ignored, allowed takes precedence IgnoreForBatchRequestAttribute ignoreAttribute = routeEndpoint.Metadata.GetMetadata <IgnoreForBatchRequestAttribute>(); AllowForBatchRequestAttribute allowAttribute = routeEndpoint.Metadata.GetMetadata <AllowForBatchRequestAttribute>(); if (ignoreAttribute != null && allowAttribute == null) { return(EndpointMatchResult.Ignored); } return(EndpointMatchResult.Match); } return(EndpointMatchResult.NoMatch); }
public void CreatesRoutes(string pattern, string resultingTemplate, string resultingTypes) { var contentTypeA = new ContentTypeDescriptor("sit", typeof(ContentTypeA)); var contentTypeB = new ContentTypeDescriptor("dol", typeof(ContentTypeB)); var contentTypeProvider = Mock.Of <IContentTypeProvider>(); Mock.Get(contentTypeProvider).Setup(p => p.GetAll()).Returns(new List <ContentTypeDescriptor> { contentTypeA, contentTypeB }); var contentTypeExpander = Mock.Of <IContentTypeExpander>(); Mock.Get(contentTypeExpander).Setup(e => e.Expand("expandToDol")).Returns(new List <ContentTypeDescriptor> { contentTypeB }); var endpoint = new RouteEndpoint(async context => { }, RoutePatternFactory.Parse(pattern), 0, null, null); var dataSource = new CompositeEndpointDataSource(new List <EndpointDataSource> { new DefaultEndpointDataSource(endpoint) }); var results = new ContentRouteCreator(Mock.Of <ILogger <ContentRouteCreator> >(), dataSource, contentTypeProvider, contentTypeExpander).Create(); if (resultingTemplate == null) { Assert.Empty(results); return; } Assert.Single(results); var result = results.Single(); Assert.Equal(resultingTemplate, result.Template); Assert.Equal(resultingTypes, string.Join(",", result.ContentTypes.Select(t => t.Id))); }
public void Matcher_IgnoresUpdate_WhenDisposed() { // Arrange var dataSource = new DynamicEndpointDataSource(); var lifetime = new DataSourceDependentMatcher.Lifetime(); var matcher = new DataSourceDependentMatcher(dataSource, lifetime, TestMatcherBuilder.Create); var endpoint = new RouteEndpoint( TestConstants.EmptyRequestDelegate, RoutePatternFactory.Parse("a/b/c"), 0, EndpointMetadataCollection.Empty, "test"); lifetime.Dispose(); // Act dataSource.AddEndpoint(endpoint); // Assert var inner = Assert.IsType <TestMatcher>(matcher.CurrentMatcher); Assert.Empty(inner.Endpoints); }
internal TemplateBinder GetTemplateBinder(RouteEndpoint endpoint) => _cache.EnsureInitialized().GetOrAdd(endpoint, _createTemplateBinder);
private TemplateBinder CreateTemplateBinder(RouteEndpoint endpoint) { return(_binderFactory.Create(endpoint.RoutePattern)); }
public IEnumerable <Endpoint> FindEndpoints(RouteValuesAddress address) { if (address.AmbientValues == null || address.ExplicitValues == null) { return(Enumerable.Empty <Endpoint>()); } // Try to get the contained item first, then the container content item string contentItemId = address.ExplicitValues[_options.ContainedContentItemIdKey]?.ToString(); if (string.IsNullOrEmpty(contentItemId)) { contentItemId = address.ExplicitValues[_options.ContentItemIdKey]?.ToString(); } if (string.IsNullOrEmpty(contentItemId)) { return(Enumerable.Empty <Endpoint>()); } (var found, var autorouteEntry) = _entries.TryGetEntryByContentItemIdAsync(contentItemId).GetAwaiter().GetResult(); if (!found) { return(Enumerable.Empty <Endpoint>()); } if (Match(address.ExplicitValues)) { // Once we have the contained content item id value we no longer want it in the route values. address.ExplicitValues.Remove(_options.ContainedContentItemIdKey); var routeValues = new RouteValueDictionary(address.ExplicitValues); if (address.ExplicitValues.Count > _options.GlobalRouteValues.Count + 1) { foreach (var entry in address.ExplicitValues) { if (String.Equals(entry.Key, _options.ContentItemIdKey, StringComparison.OrdinalIgnoreCase)) { continue; } if (!_options.GlobalRouteValues.ContainsKey(entry.Key)) { routeValues.Remove(entry.Key); } } } var endpoint = new RouteEndpoint ( c => null, RoutePatternFactory.Parse(autorouteEntry.Path, routeValues, null), 0, null, null ); return(new[] { endpoint }); } return(Enumerable.Empty <Endpoint>()); }
public TrivialMatcher(RouteEndpoint endpoint) { _endpoint = endpoint; _candidates = new Candidate[] { new Candidate(endpoint), }; }
public static OpenApiDocument CreateDocument(HttpContext context, string prefixName) { IDictionary <string, ODataPath> tempateToPathDict = new Dictionary <string, ODataPath>(); ODataOpenApiPathProvider provider = new ODataOpenApiPathProvider(); IEdmModel model = null; EndpointDataSource dataSource = context.RequestServices.GetRequiredService <EndpointDataSource>(); foreach (var endpoint in dataSource.Endpoints) { IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata == null) { continue; } if (metadata.Prefix != prefixName) { continue; } model = metadata.Model; RouteEndpoint routeEndpoint = endpoint as RouteEndpoint; if (routeEndpoint == null) { continue; } // get rid of the prefix int length = prefixName.Length; string routePathTemplate = routeEndpoint.RoutePattern.RawText.Substring(length); routePathTemplate = routePathTemplate.StartsWith("/") ? routePathTemplate : "/" + routePathTemplate; if (tempateToPathDict.TryGetValue(routePathTemplate, out ODataPath pathValue)) { var methods = GetHttpMethods(endpoint); foreach (var method in methods) { pathValue.HttpMethods.Add(method); } continue; } var path = metadata.Template.Translate(); if (path == null) { continue; } path.PathTemplate = routePathTemplate; provider.Add(path); var method1 = GetHttpMethods(endpoint); foreach (var method in method1) { path.HttpMethods.Add(method); } tempateToPathDict[routePathTemplate] = path; } OpenApiConvertSettings settings = new OpenApiConvertSettings { PathProvider = provider, ServiceRoot = BuildAbsolute(context, prefixName) }; return(model.ConvertToOpenApi(settings)); }
private static ApiDescription CreateApiDescription( RouteEndpoint routeEndpoint, MethodModel methodModel, HttpMethodAttribute httpMethodAttribute) { var apiDescription = new ApiDescription { HttpMethod = httpMethodAttribute.Method, ActionDescriptor = new ActionDescriptor { RouteValues = new Dictionary <string, string> { // Swagger uses this to group endpoints together. // Group methods together using the service name. ["controller"] = methodModel.MethodInfo.DeclaringType?.Name ?? string.Empty } }, RelativePath = routeEndpoint.RoutePattern.RawText?.TrimStart('/') ?? string.Empty }; apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat { MediaType = "application/json" }); var responseTypes = methodModel.MethodInfo .GetCustomAttributes(typeof(ProducesResponseTypeAttribute), false) .OfType <ProducesResponseTypeAttribute>(); var addDefaultResponseType = true; foreach (var responseType in responseTypes) { addDefaultResponseType = false; apiDescription.SupportedResponseTypes.Add(new ApiResponseType { ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, ModelMetadata = responseType.Type == null ? null : new ExpressModelMetadata(responseType.Type), StatusCode = responseType.StatusCode, }); } if (addDefaultResponseType) { apiDescription.SupportedResponseTypes.Add(new ApiResponseType { ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, StatusCode = 200, }); } foreach (var parameter in methodModel.Parameters) { apiDescription.ParameterDescriptions.Add(new ApiParameterDescription { Name = parameter.Name ?? "Input", ModelMetadata = new ExpressModelMetadata(parameter.ParameterType), Source = parameter.GetBindingSource() }); } return(apiDescription); }
private static bool SupportsLinkGeneration(RouteEndpoint endpoint) { return(!(endpoint.Metadata.GetMetadata <ISuppressLinkGenerationMetadata>()?.SuppressLinkGeneration == true)); }
private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint) { var httpMethodMetadata = routeEndpoint.Metadata.GetMetadata <HttpMethodMetadata>(); var verb = httpMethodMetadata?.HttpMethods.FirstOrDefault(); var apiDescription = new Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription(); // Default to a GET in case a Route map was registered inline - it's unlikely to be a composition handler in that case. apiDescription.HttpMethod = verb ?? "GET"; apiDescription.ActionDescriptor = new ActionDescriptor { RouteValues = new Dictionary <string, string> { // Swagger uses this to group endpoints together. // Group methods together using the service name. // NOTE: Need a metadata model in service composer to begin supplying more info other than just http verbs and route patterns. ["controller"] = "ViewModelComposition"// routeEndpoint.RoutePattern.GetParameter("controller").Default.ToString() } }; apiDescription.RelativePath = routeEndpoint.RoutePattern.RawText.TrimStart('/'); apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat { MediaType = "application/json" }); foreach (var producesDefaultResponseTypeAttribute in routeEndpoint.Metadata.OfType <ProducesDefaultResponseTypeAttribute>()) { apiDescription.SupportedResponseTypes.Add(new ApiResponseType { Type = producesDefaultResponseTypeAttribute.Type, ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, StatusCode = producesDefaultResponseTypeAttribute.StatusCode, IsDefaultResponse = true, ModelMetadata = _modelMetadataProvider.GetMetadataForType(producesDefaultResponseTypeAttribute.Type) }); } foreach (var producesResponseTypeAttribute in routeEndpoint.Metadata.OfType <ProducesResponseTypeAttribute>()) { apiDescription.SupportedResponseTypes.Add(new ApiResponseType { Type = producesResponseTypeAttribute.Type, ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, StatusCode = producesResponseTypeAttribute.StatusCode, IsDefaultResponse = false, ModelMetadata = _modelMetadataProvider.GetMetadataForType(producesResponseTypeAttribute.Type) }); } foreach (var apiParameterDescriptionAttribute in routeEndpoint.Metadata.OfType <ApiParameterDescriptionAttribute>()) { apiDescription.ParameterDescriptions.Add(new ApiParameterDescription() { Name = apiParameterDescriptionAttribute.Name, IsRequired = apiParameterDescriptionAttribute.IsRequired, Type = apiParameterDescriptionAttribute.Type, Source = GetBindingSource(apiParameterDescriptionAttribute.Source), ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiParameterDescriptionAttribute.Type) }); } return(apiDescription); }
public override void AddEndpoint(RouteEndpoint endpoint) { _endpoints.Add(endpoint); }
private void ProcessSegment( RouteEndpoint endpoint, List <DfaNode> parents, List <DfaNode> nextParents, RoutePatternPathSegment segment) { for (var i = 0; i < parents.Count; i++) { var parent = parents[i]; var part = segment.Parts[0]; var parameterPart = part as RoutePatternParameterPart; if (segment.IsSimple && part is RoutePatternLiteralPart literalPart) { AddLiteralNode(_includeLabel, nextParents, parent, literalPart.Content); } else if (segment.IsSimple && parameterPart != null && parameterPart.IsCatchAll) { // A catch all should traverse all literal nodes as well as parameter nodes // we don't need to create the parameter node here because of ordering // all catchalls will be processed after all parameters. if (parent.Literals != null) { nextParents.AddRange(parent.Literals.Values); } if (parent.Parameters != null) { nextParents.Add(parent.Parameters); } // We also create a 'catchall' here. We don't do further traversals // on the catchall node because only catchalls can end up here. The // catchall node allows us to capture an unlimited amount of segments // and also to match a zero-length segment, which a parameter node // doesn't allow. if (parent.CatchAll == null) { parent.CatchAll = new DfaNode() { PathDepth = parent.PathDepth + 1, Label = _includeLabel ? parent.Label + "{*...}/" : null, }; // The catchall node just loops. parent.CatchAll.Parameters = parent.CatchAll; parent.CatchAll.CatchAll = parent.CatchAll; } parent.CatchAll.AddMatch(endpoint); } else if (segment.IsSimple && parameterPart != null && TryGetRequiredValue(endpoint.RoutePattern, parameterPart, out var requiredValue)) { // If the parameter has a matching required value, replace the parameter with the required value // as a literal. This should use the parameter's transformer (if present) // e.g. Template: Home/{action}, Required values: { action = "Index" }, Result: Home/Index AddRequiredLiteralValue(endpoint, nextParents, parent, parameterPart, requiredValue); } else if (segment.IsSimple && parameterPart != null) { if (parent.Parameters == null) { parent.Parameters = new DfaNode() { PathDepth = parent.PathDepth + 1, Label = _includeLabel ? parent.Label + "{...}/" : null, }; } if (parent.Literals != null) { // If the parameter contains constraints, we can be smarter about it and evaluate them while we build the tree. // If the literal doesn't match any of the constraints, we can prune the branch. // For example, for a parameter in a route {lang:length(2)} and a parent literal "ABC", we can check that "ABC" // doesn't meet the parameter constraint (length(2)) when building the tree, and avoid the extra nodes. if (endpoint.RoutePattern.ParameterPolicies.TryGetValue(parameterPart.Name, out var parameterPolicyReferences)) { // We filter out sibling literals that don't match one of the constraints in the segment to avoid adding nodes to the DFA // that will never match a route and which will result in a much higher memory usage. AddParentsWithMatchingLiteralConstraints(nextParents, parent, parameterPart, parameterPolicyReferences); } else { // This means the current parameter we are evaluating doesn't contain any constraint, so we need to // traverse all literal nodes as well as the parameter node. nextParents.AddRange(parent.Literals.Values); } } nextParents.Add(parent.Parameters); } else { // Complex segment - we treat these are parameters here and do the // expensive processing later. We don't want to spend time processing // complex segments unless they are the best match, and treating them // like parameters in the DFA allows us to do just that. if (parent.Parameters == null) { parent.Parameters = new DfaNode() { PathDepth = parent.PathDepth + 1, Label = _includeLabel ? parent.Label + "{...}/" : null, }; } if (parent.Literals != null) { // For a complex segment like this, we can evaluate the literals and avoid adding extra nodes to // the tree on cases where the literal won't ever be able to match the complex parameter. // For example, if we have a complex parameter {a}-{b}.{c?} and a literal "Hello" we can guarantee // that it will never be a match. // We filter out sibling literals that don't match the complex parameter segment to avoid adding nodes to the DFA // that will never match a route and which will result in a much higher memory usage. AddParentsMatchingComplexSegment(endpoint, nextParents, segment, parent, parameterPart); } nextParents.Add(parent.Parameters); } } }
public ContentResult GetAllRoutes() { StringBuilder nonSb = new StringBuilder(); StringBuilder sb = new StringBuilder(); foreach (var endpoint in _dataSource.Endpoints) { ControllerActionDescriptor controllerActionDescriptor = endpoint.Metadata.GetMetadata <ControllerActionDescriptor>(); if (controllerActionDescriptor == null) { continue; } IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata == null) { AppendNonODataRoute(nonSb, endpoint); continue; } // controller and action details StringBuilder action = new StringBuilder(); if (controllerActionDescriptor.MethodInfo.ReturnType != null) { action.Append(controllerActionDescriptor.MethodInfo.ReturnType.Name + " "); } else { action.Append("void "); } action.Append(controllerActionDescriptor.MethodInfo.Name + "("); action.Append(string.Join(",", controllerActionDescriptor.MethodInfo.GetParameters().Select(p => p.ParameterType.Name))); action.Append(")"); string actionName = controllerActionDescriptor.MethodInfo.Name; sb.Append("<tr>"); sb.Append($"<td>{GetActionDesciption(controllerActionDescriptor)}</td>"); // http methods // string httpMethods = string.Join(",", metadata.HttpMethods); // sb.Append($"<td>{httpMethods.ToUpper()}</td>"); sb.Append($"<td>{string.Join(",", GetHttpMethods(endpoint))}</td>"); // template name RouteEndpoint routeEndpoint = endpoint as RouteEndpoint; if (routeEndpoint != null) { sb.Append("<td>~/").Append(routeEndpoint.RoutePattern.RawText).Append("</td></tr>"); } else { sb.Append("<td>---NON RouteEndpoint---</td></tr>"); } } string output = ODataRouteMappingHtmlTemplate.Replace("{CONTENT}", sb.ToString()); output = output.Replace("{NONENDPOINTCONTENT}", nonSb.ToString()); return(base.Content(output, "text/html")); }
private static ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint, HttpRule httpRule, MethodDescriptor methodDescriptor, string pattern, string verb) { var apiDescription = new ApiDescription(); apiDescription.HttpMethod = verb; apiDescription.ActionDescriptor = new ActionDescriptor { RouteValues = new Dictionary <string, string?> { // Swagger uses this to group endpoints together. // Group methods together using the service name. ["controller"] = methodDescriptor.Service.FullName }, EndpointMetadata = routeEndpoint.Metadata.ToList() }; apiDescription.RelativePath = pattern.TrimStart('/'); apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat { MediaType = "application/json" }); apiDescription.SupportedResponseTypes.Add(new ApiResponseType { ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, ModelMetadata = new GrpcModelMetadata(ModelMetadataIdentity.ForType(methodDescriptor.OutputType.ClrType)), StatusCode = 200 }); var explorerSettings = routeEndpoint.Metadata.GetMetadata <ApiExplorerSettingsAttribute>(); if (explorerSettings != null) { apiDescription.GroupName = explorerSettings.GroupName; } var methodMetadata = routeEndpoint.Metadata.GetMetadata <GrpcMethodMetadata>() !; var routeParameters = ServiceDescriptorHelpers.ResolveRouteParameterDescriptors(routeEndpoint.RoutePattern, methodDescriptor.InputType); foreach (var routeParameter in routeParameters) { var field = routeParameter.Value.Last(); var parameterName = ServiceDescriptorHelpers.FormatUnderscoreName(field.Name, pascalCase: true, preservePeriod: false); var propertyInfo = field.ContainingType.ClrType.GetProperty(parameterName); // If from a property, create model as property to get its XML comments. var identity = propertyInfo != null ? ModelMetadataIdentity.ForProperty(propertyInfo, MessageDescriptorHelpers.ResolveFieldType(field), field.ContainingType.ClrType) : ModelMetadataIdentity.ForType(MessageDescriptorHelpers.ResolveFieldType(field)); apiDescription.ParameterDescriptions.Add(new ApiParameterDescription { Name = routeParameter.Key, ModelMetadata = new GrpcModelMetadata(identity), Source = BindingSource.Path, DefaultValue = string.Empty }); } var bodyDescriptor = ServiceDescriptorHelpers.ResolveBodyDescriptor(httpRule.Body, methodMetadata.ServiceType, methodDescriptor); if (bodyDescriptor != null) { // If from a property, create model as property to get its XML comments. var identity = bodyDescriptor.PropertyInfo != null ? ModelMetadataIdentity.ForProperty(bodyDescriptor.PropertyInfo, bodyDescriptor.Descriptor.ClrType, bodyDescriptor.PropertyInfo.DeclaringType !) : ModelMetadataIdentity.ForType(bodyDescriptor.Descriptor.ClrType); // Or if from a parameter, create model as parameter to get its XML comments. var parameterDescriptor = bodyDescriptor.ParameterInfo != null ? new ControllerParameterDescriptor { ParameterInfo = bodyDescriptor.ParameterInfo } : null; apiDescription.ParameterDescriptions.Add(new ApiParameterDescription { Name = "Input", ModelMetadata = new GrpcModelMetadata(identity), Source = BindingSource.Body, ParameterDescriptor = parameterDescriptor ! });