在IRouter实现ASP.NET Core MVC上获得404

时间:2016-06-23 02:24:28

标签: c# asp.net-core asp.net-mvc-routing asp.net-core-mvc

我试图实现自己的动态路由器,我的计划是从我的数据库中提取路线并创建一组动态着陆页,我的问题是我在设置上下文后得到404。 RouteData到我的新路线数据。

我只是想在每次找到路线时重定向到我的LandingPageController和Index IActionResult。

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" };
        }
    }
}

我查看了这个answer,但似乎过时的情况下,某些属性在RC2中甚至不再存在。

我错过了什么?

2 个答案:

答案 0 :(得分:2)

它似乎不是最好的解决方案,但从我的测试来看,它应该适合您的要求。

我将默认MVC IRouter注入您的LandingPageRouter。然后,一旦更新了路由数据,只需调用默认路由器并传入上下文:

public class LandingPageRouter : IRouter
{
    private readonly IRouter _router;

    public LandingPageRouter(IRouter router)
    {
        _router = router;
    }

    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 _router.RouteAsync(context);
        }

        return Task.FromResult(0);
    }

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

然后只需在Startup.Configure中添加路线的位置插入默认路线:

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

答案 1 :(得分:0)

基于这个answer和@sock方法,我传递了路由构建器,它将同时传递路由器上下文

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);
}

startup.cs中的路由配置

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

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