Kit.Core/LibCommon/Kit.Core.Helpers/Routes/RouteHelpers.cs

133 lines
5.0 KiB
C#

namespace Kit.Helpers.Routes
{
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Reflection;
public class ControllerMethod
{
public string Name { get; }
public string Controller { get; }
public string RouteTemplate { get; }
public string Method => _route.GetMethod();
public MethodInfo MethodInfo { get; }
public RouteValueDictionary RouteDataTokens
{
get
{
var result = new RouteValueDictionary();
_route.Route.DataTokens?.ForEach(x => result.Add(x.Key, x.Value));
return result;
}
}
private RouteFluent _route { get; }
public ControllerMethod(string name, MethodInfo methodInfo, RouteFluent route)
{
MethodInfo = methodInfo;
_route = route;
Name = name;
Controller = _route.Route?.Defaults["controller"]?.ToString() ?? string.Empty;
RouteTemplate = _route.Route?.RouteTemplate ?? string.Empty;
}
}
public static class RouteHelper_Extensions
{
public static List<ControllerMethod> ControllerMethods = new List<ControllerMethod>();
private static IInlineConstraintResolver CreateInlineConstraintResolver(IServiceProvider serviceProvider)
{
var inlineConstraintResolver = serviceProvider
.GetRequiredService<IInlineConstraintResolver>();
var parameterPolicyFactory = serviceProvider
.GetRequiredService<ParameterPolicyFactory>();
// This inline constraint resolver will return a null constraint for non-IRouteConstraint
// parameter policies so Route does not error
return new BackCompatInlineConstraintResolver(inlineConstraintResolver, parameterPolicyFactory);
}
internal class NullRouteConstraint : IRouteConstraint
{
public static readonly NullRouteConstraint Instance = new NullRouteConstraint();
private NullRouteConstraint()
{
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
return true;
}
}
private class BackCompatInlineConstraintResolver : IInlineConstraintResolver
{
private readonly IInlineConstraintResolver _inner;
private readonly ParameterPolicyFactory _parameterPolicyFactory;
public BackCompatInlineConstraintResolver(IInlineConstraintResolver inner, ParameterPolicyFactory parameterPolicyFactory)
{
_inner = inner;
_parameterPolicyFactory = parameterPolicyFactory;
}
public IRouteConstraint ResolveConstraint(string inlineConstraint)
{
var routeConstraint = _inner.ResolveConstraint(inlineConstraint);
if (routeConstraint != null)
{
return routeConstraint;
}
var parameterPolicy = _parameterPolicyFactory.Create(null, inlineConstraint);
if (parameterPolicy != null)
{
// Logic inside Route will skip adding NullRouteConstraint
return NullRouteConstraint.Instance;
}
return null;
}
}
public static RouteFluent AddRoute(this IRouteBuilder routeBuilder, string name, string url, string controller, string action, MethodInfo methodInfo)
{
var inline = CreateInlineConstraintResolver(routeBuilder.ServiceProvider);
var route = new Route(routeBuilder.DefaultHandler, name, url, new RouteValueDictionary(new { controller = controller, action = action }), null, null, inline);
routeBuilder.Routes.Add(route);
var result = new RouteFluent { Route = route };
ControllerMethods.Add(new ControllerMethod(name, methodInfo, result));
return result;
}
public static ControllerBaseRouteFluent<TController> AddControllerBase<TController>(this IRouteBuilder routeTable)
where TController : ControllerBase
{
return new ControllerBaseRouteFluent<TController>(routeTable);
}
public static ControllerRouteFluent<TController> AddController<TController>(this IRouteBuilder routeTable)
where TController : Controller
{
return new ControllerRouteFluent<TController>(routeTable);
}
public static RouteBase GetBaseRoute(this ControllerContext context)
{
return context.GetBaseRoute();
}
public static bool GetForbidForReadonly(this RouteData route)
{
return (route.DataTokens["forbidForReadonly"] as bool?) ?? false;
}
}
}