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) { AppendRoute(nonSb, endpoint); } else { AppendRoute(sb, endpoint); } } string output = ODataRouteMappingHtmlTemplate.Replace("ODATACONTENT", sb.ToString(), StringComparison.OrdinalIgnoreCase); output = output.Replace("NONENDPOINTCONTENT", nonSb.ToString(), StringComparison.OrdinalIgnoreCase); return(base.Content(output, "text/html")); }
public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } // The goal of this method is to perform the final matching: // Map between route values matched by the template and the ones we want to expose to the action for binding. // (tweaking the route values is fine here) // Invalidating the candidate if the key/function values are not valid/missing. // Perform overload resolution for functions by looking at the candidates and their metadata. for (var i = 0; i < candidates.Count; i++) { ref CandidateState candidate = ref candidates[i]; if (!candidates.IsValidCandidate(i)) { continue; } IODataRoutingMetadata metadata = candidate.Endpoint.Metadata.OfType <IODataRoutingMetadata>().FirstOrDefault(); if (metadata == null) { continue; } IHttpMethodMetadata httpMetadata = candidate.Endpoint.Metadata.GetMetadata <IHttpMethodMetadata>(); if (httpMetadata == null) { // Check the http method if (metadata.HttpMethods != null && !metadata.HttpMethods.Contains(httpContext.Request.Method)) { candidates.SetValidity(i, false); continue; } } ODataTemplateTranslateContext translatorContext = new ODataTemplateTranslateContext(httpContext, candidate.Values, metadata.Model); try { ODataPath odataPath = _translator.Translate(metadata.Template, translatorContext); if (odataPath != null) { IODataFeature odataFeature = httpContext.ODataFeature(); odataFeature.PrefixName = metadata.Prefix; odataFeature.Model = metadata.Model; odataFeature.Path = odataPath; } else { candidates.SetValidity(i, false); } } catch (Exception) { candidates.SetValidity(i, false); } }
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>"); // 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 OpenApiDocument CreateDocument(string prefixName) { IDictionary <string, ODataPath> tempateToPathDict = new Dictionary <string, ODataPath>(); ODataOpenApiPathProvider provider = new ODataOpenApiPathProvider(); IEdmModel model = null; 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)) { string method = GetHttpMethod(metadata, endpoint); pathValue.HttpMethods.Add(method); continue; } var path = metadata.Template.Translate(); if (path == null) { continue; } path.PathTemplate = routePathTemplate; provider.Add(path); string method1 = GetHttpMethod(metadata, endpoint); path.HttpMethods.Add(method1); tempateToPathDict[routePathTemplate] = path; } OpenApiConvertSettings settings = new OpenApiConvertSettings { PathProvider = provider, ServiceRoot = BuildAbsolute() }; return(model.ConvertToOpenApi(settings)); }
public IEnumerable <EndpointRouteInfo> GetAllRoutes() { if (_dataSource == null) { return(Enumerable.Empty <EndpointRouteInfo>()); } IList <EndpointRouteInfo> routeInfos = new List <EndpointRouteInfo>(); foreach (var endpoint in _dataSource.Endpoints) { RouteEndpoint routeEndpoint = endpoint as RouteEndpoint; if (routeEndpoint == null) { continue; } ControllerActionDescriptor controllerActionDescriptor = endpoint.Metadata.GetMetadata <ControllerActionDescriptor>(); if (controllerActionDescriptor == null) { continue; } EndpointRouteInfo routeInfo = new EndpointRouteInfo(); 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(")"); routeInfo.ControllerFullName = controllerActionDescriptor.ControllerTypeInfo.FullName; routeInfo.ActionFullName = action.ToString(); routeInfo.Template = routeEndpoint.RoutePattern.RawText; var httpMethods = GetHttpMethods(endpoint); routeInfo.HttpMethods = string.Join(",", httpMethods); IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata == null) { routeInfo.IsODataRoute = false; } else { routeInfo.IsODataRoute = true; } routeInfos.Add(routeInfo); } return(routeInfos); }
internal async Task HandleJsonEndpointsAsync(HttpContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } List <EndpointRouteInfo> infos = new List <EndpointRouteInfo>(); EndpointDataSource dataSource = context.RequestServices.GetRequiredService <EndpointDataSource>(); foreach (var endpoint in dataSource.Endpoints) { ControllerActionDescriptor controllerActionDescriptor = endpoint.Metadata.GetMetadata <ControllerActionDescriptor>(); if (controllerActionDescriptor == null) { continue; } EndpointRouteInfo info = new EndpointRouteInfo { DisplayName = endpoint.DisplayName, HttpMethods = string.Join(",", GetHttpMethods(endpoint)), }; // template name RouteEndpoint routeEndpoint = endpoint as RouteEndpoint; if (routeEndpoint != null) { info.Template = routeEndpoint.RoutePattern.RawText; } else { info.Template = "N/A"; } IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata == null) { info.IsODataRoute = false; } else { info.IsODataRoute = true; } infos.Add(info); } JsonSerializerOptions options = new JsonSerializerOptions() { WriteIndented = true }; string output = JsonSerializer.Serialize(infos, options); context.Response.Headers["Content_Type"] = "application/json"; await context.Response.WriteAsync(output).ConfigureAwait(false); }
/// <summary> /// Execute for second pass for OData API description. /// </summary> /// <param name="context">The ApiDescriptionProviderContext.</param> public void OnProvidersExecuted(ApiDescriptionProviderContext context) { foreach (var action in context?.Actions) { IODataRoutingMetadata odataMetadata = action.EndpointMetadata.OfType <IODataRoutingMetadata>().FirstOrDefault(); if (odataMetadata != null) { ApiDescription apiDes = context.Results.FirstOrDefault(r => r.ActionDescriptor == action); if (apiDes != null) { apiDes.RelativePath = odataMetadata.TemplateDisplayName; } } } }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/error"); } app.UseHttpsRedirection(); // Add the OData Batch middleware to support OData $Batch //app.UseODataBatching(); // call before "UseRouting" app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // Test middelware app.Use(next => context => { var endpoint = context.GetEndpoint(); if (endpoint == null) { return(next(context)); } IEnumerable <string> templates; IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata != null) { templates = metadata.Template.GetTemplates(); } return(next(context)); }); //app.UseMiddleware<JwtMiddleware>(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
private static string GetHttpMethod(IODataRoutingMetadata metadata, Endpoint endpoint) { string method = metadata.HttpMethods.FirstOrDefault(); if (method != null) { return(method); } HttpMethodMetadata methodMetadata = endpoint.Metadata.GetMetadata <HttpMethodMetadata>(); if (methodMetadata != null) { return(methodMetadata.HttpMethods.First()); } throw new Exception(); }
private static RouteEndpoint CreateEndpoint(string template, IODataRoutingMetadata odataMetadata, params object[] more) { var metadata = new List <object>(); if (odataMetadata != null) { metadata.Add(odataMetadata); } if (more != null) { metadata.AddRange(more); } return(new RouteEndpoint( (context) => Task.CompletedTask, RoutePatternFactory.Parse(template), 0, new EndpointMetadataCollection(metadata), $"test: {template} - { odataMetadata?.Prefix ?? ""}")); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseODataBatching(); app.UseRouting(); // Test middelware app.Use(next => context => { var endpoint = context.GetEndpoint(); if (endpoint == null) { return(next(context)); } IEnumerable <string> templates; IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata != null) { templates = metadata.Template.GetTemplates(); } return(next(context)); }); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
internal async Task HandleEndpointsAsync(HttpContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } StringBuilder nonSb = new StringBuilder(); StringBuilder sb = new StringBuilder(); EndpointDataSource dataSource = context.RequestServices.GetRequiredService <EndpointDataSource>(); 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) { AppendRoute(nonSb, endpoint); } else { AppendRoute(sb, endpoint); } } string output = ODataRouteMappingHtmlTemplate.Replace("ODATACONTENT", sb.ToString(), StringComparison.Ordinal); output = output.Replace("NONENDPOINTCONTENT", nonSb.ToString(), StringComparison.Ordinal); context.Response.Headers["Content_Type"] = "text/html"; await context.Response.WriteAsync(output).ConfigureAwait(false); }
/// <summary> /// Applies the policy to the CandidateSet. /// </summary> /// <param name="httpContext">The context associated with the current request.</param> /// <param name="candidates">The CandidateSet.</param> /// <returns>The task.</returns> public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) { if (httpContext == null) { throw Error.ArgumentNull(nameof(httpContext)); } IODataFeature odataFeature = httpContext.ODataFeature(); if (odataFeature.Path != null) { // If we have the OData path setting, it means there's some Policy working. // Let's skip this default OData matcher policy. return(Task.CompletedTask); } // The goal of this method is to perform the final matching: // Map between route values matched by the template and the ones we want to expose to the action for binding. // (tweaking the route values is fine here) // Invalidating the candidate if the key/function values are not valid/missing. // Perform overload resolution for functions by looking at the candidates and their metadata. for (var i = 0; i < candidates.Count; i++) { ref CandidateState candidate = ref candidates[i]; if (!candidates.IsValidCandidate(i)) { continue; } IODataRoutingMetadata metadata = candidate.Endpoint.Metadata.OfType <IODataRoutingMetadata>().FirstOrDefault(); if (metadata == null) { continue; } if (odataFeature.Path != null) { // If it's odata endpoint, and we have a path set, let other odata endpoints invalid. candidates.SetValidity(i, false); continue; } ODataTemplateTranslateContext translatorContext = new ODataTemplateTranslateContext(httpContext, candidate.Endpoint, candidate.Values, metadata.Model); ODataPath odataPath = _translator.Translate(metadata.Template, translatorContext); if (odataPath != null) { odataFeature.RoutePrefix = metadata.Prefix; odataFeature.Model = metadata.Model; odataFeature.Path = odataPath; MergeRouteValues(translatorContext.UpdatedValues, candidate.Values); // Shall we break the remaining candidates? // So far the answer is no. Because we can use this matcher to obsolete the unmatched endpoint. // break; } else { candidates.SetValidity(i, false); } }
/// <summary> /// Handle ~/$odata request /// </summary> /// <param name="context">The http context.</param> /// <returns>The task.</returns> public static async Task HandleOData(HttpContext context) { EndpointDataSource dataSource = context.RequestServices.GetRequiredService <EndpointDataSource>(); StringBuilder sb = new StringBuilder(); foreach (var endpoint in dataSource.Endpoints) { IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata <IODataRoutingMetadata>(); if (metadata == null) { continue; } ControllerActionDescriptor controllerActionDescriptor = endpoint.Metadata.GetMetadata <ControllerActionDescriptor>(); if (controllerActionDescriptor == null) { 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>{controllerActionDescriptor.ControllerTypeInfo.FullName}</td>"); sb.Append($"<td>{action}</td>"); // http methods string httpMethods = string.Join(",", metadata.HttpMethods); sb.Append($"<td>{httpMethods.ToUpper()}</td>"); // OData routing templates RouteEndpoint routeEndpoint = endpoint as RouteEndpoint; if (routeEndpoint != null) { sb.Append("<td>~/").Append(routeEndpoint.RoutePattern.RawText).Append("</td></tr>"); } else { int index = 1; sb.Append("<td>"); foreach (var template in metadata.Template.GetTemplates()) { sb.Append($"{index++})"); if (string.IsNullOrEmpty(metadata.Prefix)) { sb.Append(" ~/"); } else { sb.Append($" ~/{metadata.Prefix}/"); } sb.Append(template).Append("<br/>"); } sb.Append("</td></tr>"); } } string output = ODataRouteMappingHtmlTemplate.Replace("{CONTNET}", sb.ToString()); context.Response.Headers["Content_Type"] = "text/html"; await context.Response.WriteAsync(output); //string content = sb.ToString(); //byte[] requestBytes = Encoding.UTF8.GetBytes(content); //context.Response.Headers.ContentLength = requestBytes.Length; //context.Response.Body = new MemoryStream(requestBytes); //await Task.CompletedTask; }
public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } IODataFeature odataFeature = httpContext.ODataFeature(); if (odataFeature.Path != null) { // If we have the OData path setting, it means there's some Policy working. // Let's skip this default OData matcher policy. return(Task.CompletedTask); } for (var i = 0; i < candidates.Count; i++) { ref CandidateState candidate = ref candidates[i]; if (!candidates.IsValidCandidate(i)) { continue; } IODataRoutingMetadata metadata = candidate.Endpoint.Metadata.OfType <IODataRoutingMetadata>().FirstOrDefault(); if (metadata == null) { continue; } // Get api-version query from HttpRequest? QueryStringApiVersionReader reader = new QueryStringApiVersionReader("api-version"); string apiVersionStr = reader.Read(httpContext.Request); if (apiVersionStr == null) { candidates.SetValidity(i, false); continue; } ApiVersion apiVersion = ApiVersion.Parse(apiVersionStr); IEdmModel model = GetEdmModel(apiVersion); if (model == null) { candidates.SetValidity(i, false); continue; } if (!IsApiVersionMatch(candidate.Endpoint.Metadata, apiVersion)) { candidates.SetValidity(i, false); continue; } ODataTemplateTranslateContext translatorContext = new ODataTemplateTranslateContext(httpContext, candidate.Endpoint, candidate.Values, model); try { ODataPath odataPath = _translator.Translate(metadata.Template, translatorContext); if (odataPath != null) { odataFeature.RoutePrefix = metadata.Prefix; odataFeature.Model = model; odataFeature.Path = odataPath; ODataOptions options = new ODataOptions(); UpdateQuerySetting(options); options.AddRouteComponents(model); odataFeature.Services = options.GetRouteServices(string.Empty); MergeRouteValues(translatorContext.UpdatedValues, candidate.Values); } else { candidates.SetValidity(i, false); } } catch { candidates.SetValidity(i, false); } }