Imlementing a Custom IRouter in ASP.NET 5 (vNext) MVC 6

前端 未结 2 478
情话喂你
情话喂你 2020-12-05 18:41

I am attempting to convert this sample RouteBase implementation to work with MVC 6. I have worked out most of it by following the example in the Routing project, but I am ge

2条回答
  •  鱼传尺愫
    2020-12-05 19:12

    Primary reason why that doesn't work is because you aren't doing anything in the RouteAsync method. Another reason is that how routing works in MVC 6 is very different to how the previous MVC routing worked so you're probably be better off writing it from scratch using the source code as reference as there are very few articles that tackle MVC 6 at the moment.

    EDIT: @Daniel J.G. answer makes much more sense than this so use that if possible. This might fit someone else's use case so I'm leaving this here.

    Here's a very simple IRouter implementation using beta7. This should work but you'll probably need to fill in the gaps. You'll need to remove the page != null and replace it with the code below and replace the controllers and actions:

    if (page == null)
    {
        // Move to next router
        return;
    }
    
    // TODO: Replace with correct controller
    var controllerType = typeof(HomeController);
    // TODO: Replace with correct action
    var action = nameof(HomeController.Index);
    
    // This is used to locate the razor view
    // Remove the trailing "Controller" string
    context.RouteData.Values["Controller"] = controllerType.Name.Substring(0, controllerType.Name.Length - 10);
    
    var actionInvoker = context.HttpContext.RequestServices.GetRequiredService();
    
    var descriptor = new ControllerActionDescriptor
    {
        Name = action,
        MethodInfo = controllerType.GetTypeInfo().DeclaredMethods.Single(m => m.Name == action),
        ControllerTypeInfo = controllerType.GetTypeInfo(),
        // Setup filters
        FilterDescriptors = new List(),
        // Setup DI properties
        BoundProperties = new List(0),
        // Setup action arguments
        Parameters = new List(0),
        // Setup route constraints
        RouteConstraints = new List(0),
        // This router will work fine without these props set
        //ControllerName = "Home",
        //DisplayName = "Home",
    };
    
    var accessor = context.HttpContext.RequestServices.GetRequiredService();
    
    accessor.ActionContext = new ActionContext(context.HttpContext, context.RouteData, descriptor);
    
    var actionInvokerFactory = context.HttpContext.RequestServices.GetRequiredService();
    var invoker = actionInvokerFactory.CreateInvoker(accessor.ActionContext);
    
    // Render the page
    await invoker.InvokeAsync();
    
    // Don't execute the next IRouter
    context.IsHandled = true;
    
    return;
    

    Make sure you add a reference to the Microsoft.Framework.DependencyInjection namespace to resolve the GetRequiredService extension.

    After that, register the IRouter as per below:

    app.UseMvc(routes =>
    {
        // Run before any default IRouter implementation
        // or use .Add to run after all the default IRouter implementations
        routes.Routes.Insert(0, routes.ServiceProvider.GetRequiredService());
    
        // .. more code here ...
    });
    

    Then just register that in your IOC,

    services.AddSingleton();
    

    Another 'cleaner' approach would probably be to create a different implementation of IActionSelector.

提交回复
热议问题