Search code examples
c#asp.net-coreasp.net-mvc-routingasp.net-core-mvc

Getting 404 on IRouter implementation ASP.NET Core MVC


I'm trying to implement my own dynamic router, my plan is to pull routes from my database and create a set of dynamic landing pages, my issue is that I'm getting 404 after setting up context.RouteData to my new route data.

I just want to redirect to my LandingPageController and the Index IActionResult everytime I found a route.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Routing;
using System.Collections.Generic;
using System.Linq;

namespace Myproject.Web.Main.Config
{
    public class LandingPageRouter : IRouter
    {
        public VirtualPathData GetVirtualPath(VirtualPathContext context)
        {
            return null;
        }

        public Task RouteAsync(RouteContext context)
        {

            var requestPath = context.HttpContext.Request.Path.Value;
            if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
            {
                requestPath = requestPath.Substring(1);
            }

            var pagefound = GetPages().Any(x => x == requestPath);
            if (pagefound)
            {
                //TODO: Handle querystrings
                var routeData = new RouteData();
                routeData.Values["controller"] = "LandingPage";
                routeData.Values["action"] = "Index";
                context.RouteData = routeData;
            }

            return Task.FromResult(0);
        }

        private IEnumerable<string> GetPages()
        {
            //TODO: pull from database
            return new List<string> { "page-url-title", "another-dynamic-url" };
        }
    }
}

I looked at this answer but it seems outdated some properties in the context doesn't even exist anymore in RC2.

What Am I missing?


Solution

  • Based on this answer and @sock approach, I passed the route builder which is going to pass at the same time the router context

    public LandingPageRouter(IRouteBuilder routeBuilder)
    {
        _routeBuilder = routeBuilder;
    }
    
    public Task RouteAsync(RouteContext context)
    {
        var requestPath = context.HttpContext.Request.Path.Value;
        if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
        {
            requestPath = requestPath.Substring(1);
        }
    
        var pagefound = GetPages().SingleOrDefault(x => x.Name == requestPath);
        if (pagefound!=null)
        {
            //TODO: Handle querystrings
            var routeData = new RouteData();
            routeData.Values["controller"] = "LandingPage";
            routeData.Values["action"] = "Index";
            routeData.Values["id"] = pagefound.Id;
    
            context.RouteData = routeData;
            return _routeBuilder.DefaultHandler.RouteAsync(context);
        }
        return Task.FromResult(0);
    }
    

    Routes configuration in startup.cs

    app.UseMvc(routes =>
    {
        routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
    
        routes.Routes.Add(new LandingPageRouter(routes));
    }