Search code examples
asp.net-coreroutesasp.net-core-mvcasp.net-core-2.1

Can't change destination controller/action via IRouter


I have simple MyRouter:

public class MyRouter : IRouter
{
    private readonly IRouteBuilder _routeBuilder;

    public MyRouter(IRouteBuilder routeBuilder)
    {
        _routeBuilder = routeBuilder;
    }

    public async Task RouteAsync(RouteContext context)
    {
        if (ShouldReroute(...))
        {
            SetNeededPath(context, reroute);
        }

        await GetDefaultRouter().RouteAsync(context);
    }

    private bool ShouldReroute(...)
    {
        return true;
    }

    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    {
        return GetDefaultRouter().GetVirtualPath(context);
    }

    private IRouter GetDefaultRouter()
    {
        return _routeBuilder.DefaultHandler;
    }

    private void SetNeededPath(RouteContext context, Reroute reroute)
    {
        context.RouteData.Values.Clear();

        context.RouteData.Values["action"] = "StoreContacts";
        context.RouteData.Values["controller"] = "Information";
    }
}

As you can see it should change the destination of the request to:

[Route("")]
public class InformationController : Controller
{
    [Route("StoreContacts")]
    public IActionResult StoreContacts()
    {
        return View();
    }
}

The routers description in Startup.cs is:

        app.UseMvc(routes =>
        {
           routes.MapRoute(
                name: "areas",
                template: "{area:exists}/{controller=Home}/{action=Index}");

            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.Routes.Add(new MyRouter(routes));
        });

So in my brain, it should redirect all unmapped requests like mysite.com/unexistingRoute should go to InformationController.StoreContacts, but I get only 404.

Also the mysite.com/StoreContacts is available via the direct URL.


Solution

  • Attribute routing will take over conventional routing , so you can remove the attribute routing :

    public class InformationController : Controller
    {
    
        public IActionResult StoreContacts()
        {
            return View();
        }
    }
    

    And move your logic into custom route via IRouter . mysite.com/unexistingRoute won't map to existed route template config in Startup.cs . So remove attribute should work in your scenario . To map other url like mysite.com/OtherAction , you can write custom logic like :

    if (context.HttpContext.Request.Path.Value.StartsWith("/StoreContacts"))
    {
            context.RouteData.Values["controller"] = "Information";
            context.RouteData.Values["action"] = "StoreContacts";
    }