在ASP.NET Core的约束中重写RouteValueDictionary

时间:2019-05-26 09:33:56

标签: asp.net-core asp.net-core-mvc

我刚刚开始使用ASP.NET Core MVC,并且我希望一条路线(全局子弹)转到多个控制器和操作,具体取决于我为用户提供的页面类型。例如,我要对类别和产品页面使用{* slug}。

我试图在约束中覆盖默认的控制器和动作。

在过去的MVC版本中,您可以在约束中更改values [“ controller”]或values [“ action”],并将其重新路由到适当的控制器和动作。

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {

        app.UseMvc(routes =>
                    {
                        routes.MapRoute(
                            name: "Category",
                            template: "{*slug}",
                            defaults: new { controller = "Page", action = "Home" },
                            constraints: new { slug = new PageConstraint() }
                            );
                    });

    }

}


public partial class PageConstraint : IRouteConstraint
{
    public virtual bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.UrlGeneration)
        {
            return true;
        }

        var slug = values["slug"] != null ? values["slug"].ToString() : null;

        if (string.IsNullOrWhiteSpace(slug))
        {
            // Homepage
            return true;
        }

        // Get category service
        var categoryService = httpContext.RequestServices.GetRequiredService<ICategoryService>();

        var category = categoryService.GetBySlug(slug);

        if (category == null)
        {
            return false;
        }

        values["controller"] = "Category";
        values["action"] = "Listing";
        values["category"] = category;

        return true;
    }
}

在PageConstraint中,我查看类别是否存在,如果存在,它将RouteValueDictionary中的Controller更改为Category,将Action更改为Listing。但是,当我调试代码时,仍然会转到“控制器页面”和“ Action Home”。

任何人都知道为什么会这样,或者是否有更好的方法来做到这一点?我知道我可以在控制器中执行一个动作来完成约束的所有工作,但是我宁愿将代码存放在单独的控制器和动作中。

1 个答案:

答案 0 :(得分:0)

根据您的要求,您可以尝试实现自定义IRouter

public class RouterFromAppSettings : IRouter
{
    private readonly IRouter _defaulRouter;
    private readonly IConfiguration _config;
    public RouterFromAppSettings(IRouter defaulRouter
        , IConfiguration config)
    {
        _defaulRouter = defaulRouter;
        _config = config;
    }
    public async Task RouteAsync(RouteContext context)
    {
        var controller = _config.GetSection("Router").GetValue<string>("Controller");
        var action = _config.GetSection("Router").GetValue<string>("Action");
        context.RouteData.Values["controller"] = controller;
        context.RouteData.Values["action"] = action;
        await _defaulRouter.RouteAsync(context);
    }
    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    {
        return _defaulRouter.GetVirtualPath(context);
    }
}

然后像

一样在Startup.cs中注册
app.UseMvc(routes =>
{
    routes.Routes.Insert(0, new RouterFromAppSettings(routes.DefaultHandler,Configuration));

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