Meine Implementierung kann durch diese beiden Klassen zusammengefasst werden:
Einbinden in den ASP.NET MVC-Startcode, um TokenizedDirectRouteProvider zu registrieren:
Code: Select all
public static class RouteCollectionExtensions
{
public static void MapMvcAttributeRoutesWithTokens(this RouteCollection routes, IInlineConstraintResolver constraintResolver = null)
{
if (routes == null)
{
throw new ArgumentNullException(nameof(routes));
}
routes.MapMvcAttributeRoutes(constraintResolver ?? new DefaultInlineConstraintResolver(), new TokenizedDirectRouteProvider());
}
}
Code: Select all
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutesWithTokens();
// Conventional route for SimpleController (global)
routes.MapRoute(
name: "Simple",
url: "{controller}/{action}/{id}",
defaults: null,
constraints: new { controller = "Simple" },
namespaces: [typeof(WebProcessorLibrary.Controllers.SimpleController).Namespace]
);
}
}
Code: Select all
internal class TokenizedDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList GetControllerDirectRoutes(ControllerDescriptor controllerDescriptor, IReadOnlyList actionDescriptors, IReadOnlyList factories, IInlineConstraintResolver constraintResolver) =>
[.. actionDescriptors.SelectMany(o => GetActionDirectRoutes(o, factories, constraintResolver))];
protected override IReadOnlyList GetActionDirectRoutes(ActionDescriptor actionDescriptor, IReadOnlyList factories, IInlineConstraintResolver constraintResolver) =>
base.GetActionDirectRoutes(actionDescriptor, [.. factories.Select(f => WrapDirectRouteFactory(f, actionDescriptor))], constraintResolver);
private static IDirectRouteFactory WrapDirectRouteFactory(IDirectRouteFactory proto, ActionDescriptor actionDescriptor) =>
new TokenReplacingRouteFactory(proto, actionDescriptor);
///
/// Wrapper factory that processes tokens in route templates before creating routes.
///
private class TokenReplacingRouteFactory(IDirectRouteFactory m_innerFactory, ActionDescriptor m_actionDescriptor) : IDirectRouteFactory
{
public RouteEntry CreateRoute(DirectRouteFactoryContext context)
{
if (m_innerFactory is RouteAttribute routeAttr)
{
string template = routeAttr.Template;
if (!string.IsNullOrEmpty(template))
{
var areaName = GetAreaName(m_actionDescriptor.ControllerDescriptor);
var hasAreaToken = template.Contains("[area]");
if (!string.IsNullOrEmpty(areaName) != hasAreaToken)
{
var msg = hasAreaToken
? $"The route template '{template}' has the [area] token, but the controller '{m_actionDescriptor.ControllerDescriptor.ControllerName}' is not in an area."
: $"Controller '{m_actionDescriptor.ControllerDescriptor.ControllerName}' is in area '{areaName}', but route template '{template}' does not contain the required '[area]' token.";
throw new InvalidOperationException(msg);
}
var processedTemplate = template
.Replace("[controller]", m_actionDescriptor.ControllerDescriptor.ControllerName)
.Replace("[action]", m_actionDescriptor.ActionName)
.Replace("[area]", areaName);
// If the template contains [area] token and doesn't start with ~, prepend ~ to make it absolute
// This prevents ASP.NET Framework from adding the area prefix automatically
if (hasAreaToken && !processedTemplate.StartsWith("~"))
{
processedTemplate = "~/" + processedTemplate;
}
if (processedTemplate != template)
{
LogEx.ForContext().Debug("'{OriginalTemplate}' -> '{ProcessedTemplate}' for {Controller}.{Action}",
template, processedTemplate, m_actionDescriptor.ControllerDescriptor.ControllerName, m_actionDescriptor.ActionName);
IDirectRouteFactory newRouteFactory = new RouteAttribute(processedTemplate)
{
Name = routeAttr.Name,
Order = routeAttr.Order
};
// Create the route entry using the new factory
var routeEntry = newRouteFactory.CreateRoute(context);
if (areaName != null)
{
Debug.Assert(areaName.Equals(context.AreaPrefix));
Debug.Assert(areaName.Equals(routeEntry.Route.DataTokens["area"]));
}
return routeEntry;
}
}
}
return m_innerFactory.CreateRoute(context);
}
private string GetAreaName(ControllerDescriptor controllerDescriptor)
{
var routeAreaAttr = controllerDescriptor.GetCustomAttributes(typeof(RouteAreaAttribute), inherit: true)
.OfType()
.FirstOrDefault();
if (routeAreaAttr != null)
{
return routeAreaAttr.AreaName;
}
// Fallback: check the namespace for area name
string controllerNamespace = controllerDescriptor.ControllerType.Namespace ?? string.Empty;
var i = controllerNamespace.IndexOf(".Areas.");
if (i >= 0)
{
int j = controllerNamespace.IndexOf('.', i + 7);
if (j >= 0)
{
return controllerNamespace[(i + 7)..j];
}
}
return null;
}
}
}
Mein Problem ist die Controller.Initialize-Überschreibung:
Code: Select all
[Route("[controller]/[action]/{id?}")]
public class TestController: Controller
{
...
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
}
}
Code: Select all
var routeData = requestContext.RouteData;
routeData.Values.TryGetValue("controller", out var controller);
routeData.Values.TryGetValue("action", out var action);
routeData.Values.TryGetValue("id", out var id);
Ein Controller, der auf das konventionsbasierte Routing zurückgreift (
Code: Select all
SimpleControllerIch interessiere mich speziell für die Controller.Initialize-Methode. Und ich kann Asp.Net Core selbst nicht verwenden, obwohl ich dessen attributbasiertes Routing benötigen.
Wie kann das behoben werden?
Mobile version