2021-11-19 16:11:12 +01:00
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc.Routing;
|
|
|
|
|
using Microsoft.AspNetCore.Routing;
|
2022-01-07 12:47:37 +01:00
|
|
|
using Microsoft.Extensions.Logging;
|
2021-11-19 16:11:12 +01:00
|
|
|
|
|
|
|
|
namespace zero.Routing;
|
|
|
|
|
|
|
|
|
|
public class ZeroRoutesTransformer : DynamicRouteValueTransformer
|
|
|
|
|
{
|
2021-12-13 12:21:15 +01:00
|
|
|
readonly IRouteResolver RouteResolver;
|
2022-01-07 12:47:37 +01:00
|
|
|
readonly ILogger<ZeroRoutesTransformer> Logger;
|
2021-11-19 16:11:12 +01:00
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
public ZeroRoutesTransformer(IRouteResolver routeResolver, ILogger<ZeroRoutesTransformer> logger)
|
2021-11-19 16:11:12 +01:00
|
|
|
{
|
|
|
|
|
RouteResolver = routeResolver;
|
2022-01-07 12:47:37 +01:00
|
|
|
Logger = logger;
|
|
|
|
|
}
|
2021-11-19 16:11:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
|
|
|
|
|
{
|
2022-01-07 12:47:37 +01:00
|
|
|
if (State == null || State is not ZeroRoutesTransformerType)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(State), "Pass a ZeroRoutesTransformerType instance to the state parameter in the dynamic route transformer");
|
|
|
|
|
}
|
2021-11-19 16:11:12 +01:00
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
ZeroRoutesTransformerType type = (ZeroRoutesTransformerType)State;
|
|
|
|
|
|
|
|
|
|
IRouteEndpoint endpoint = httpContext.Features.Get<IRouteEndpoint>();
|
|
|
|
|
IRouteModel route = httpContext.Features.Get<IRouteModel>();
|
|
|
|
|
|
|
|
|
|
// check if a resolved endpoint routes to a Razor Page.
|
|
|
|
|
// if the Page transformer can't find an endpoint it exits as the Controller transformer already ran before.
|
|
|
|
|
if (type == ZeroRoutesTransformerType.Page)
|
|
|
|
|
{
|
|
|
|
|
if (endpoint is PageRouteEndpoint)
|
|
|
|
|
{
|
|
|
|
|
return Apply(httpContext, values, endpoint, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// a route was already set, therefore we prevent another execution
|
|
|
|
|
if (route != null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resolve route from URL
|
2021-11-19 16:11:12 +01:00
|
|
|
route = await RouteResolver.ResolveUrl(httpContext);
|
|
|
|
|
|
|
|
|
|
if (route == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
httpContext.Features.Set(route);
|
2021-11-19 16:11:12 +01:00
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
// map the route to an endpoint
|
|
|
|
|
// an endpoint can be a controller action or a Razor page.
|
|
|
|
|
// in case it is a Razor page we exit here and let the transformer run again within the page context (MapDynamicPageRoute).
|
|
|
|
|
endpoint = RouteResolver.MapEndpoint(route);
|
2021-11-19 16:11:12 +01:00
|
|
|
|
|
|
|
|
if (endpoint == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
httpContext.Features.Set(endpoint);
|
|
|
|
|
|
|
|
|
|
if (endpoint is PageRouteEndpoint)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Apply(httpContext, values, endpoint, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual RouteValueDictionary Apply(HttpContext httpContext, RouteValueDictionary values, IRouteEndpoint endpoint, ZeroRoutesTransformerType type)
|
|
|
|
|
{
|
|
|
|
|
endpoint.Apply(values);
|
|
|
|
|
|
|
|
|
|
HashSet<string> logValues = new();
|
|
|
|
|
|
|
|
|
|
foreach ((string key, object value) in values)
|
|
|
|
|
{
|
|
|
|
|
if (key != "url" && value != null && (value is not string || ((string)value).HasValue()))
|
|
|
|
|
{
|
|
|
|
|
logValues.Add(key + ": " + value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger.LogDebug("Routed {url} to [{values}] (transformer: {type})", httpContext.Request.Path, logValues, type);
|
|
|
|
|
|
2021-11-19 16:11:12 +01:00
|
|
|
return values;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-07 12:47:37 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
public enum ZeroRoutesTransformerType
|
|
|
|
|
{
|
|
|
|
|
Controller = 0,
|
|
|
|
|
Page = 1
|
|
|
|
|
}
|