我刚刚开始使用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”。
任何人都知道为什么会这样,或者是否有更好的方法来做到这一点?我知道我可以在控制器中执行一个动作来完成约束的所有工作,但是我宁愿将代码存放在单独的控制器和动作中。
答案 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?}");
});