如何在MVC Core中动态选择控制器

时间:2016-01-30 02:01:32

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

我的情况是网站可能需要根据数据库结果重定向到某些控制器的链接。

例如:

site.com/abcd

需要从Item Controller返回结果,通常称为/ item / view / 123

这里的关键是我不能将abcd硬编码到路由中。一些链接可能会转到项目控制器,其他链接可能会转到订单控制器。

我尝试了一个到控制器的catchall路由,然后加载了所需的控制器,但环境没有设置,因此它无法正常工作(它无法找到视图)。

1 个答案:

答案 0 :(得分:2)

您可以通过IRouter实现public class MyRoute : IRouter { private readonly IRouter innerRouter; public MyRoute(IRouter innerRouter) { if (innerRouter == null) throw new ArgumentNullException("innerRouter"); this.innerRouter = innerRouter; } public async Task RouteAsync(RouteContext context) { var requestPath = context.HttpContext.Request.Path.Value; if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/') { // Trim the leading slash requestPath = requestPath.Substring(1); } if (!requestPath.StartsWith("abcd")) { return; } //Invoke MVC controller/action var oldRouteData = context.RouteData; var newRouteData = new RouteData(oldRouteData); newRouteData.Routers.Add(this.innerRouter); newRouteData.Values["controller"] = "Item"; newRouteData.Values["action"] = "View"; newRouteData.Values["id"] = 123; try { context.RouteData = newRouteData; await this.innerRouter.RouteAsync(context); } finally { // Restore the original values to prevent polluting the route data. if (!context.IsHandled) { context.RouteData = oldRouteData; } } } public VirtualPathData GetVirtualPath(VirtualPathContext context) { VirtualPathData result = null; var values = context.Values; var controller = Convert.ToString(values["controller"]); var action = Convert.ToString(values["action"]); var id = Convert.ToString(values["id"]); if ("Item".Equals(controller) && "View".Equals(action)) { result = new VirtualPathData(this, "abcd?id=" + id); context.IsBound = true; } // IMPORTANT: Always return null if there is no match. // This tells .NET routing to check the next route that is registered. return result; } } 来获得您想要的任何行为,包括将您的逻辑基于来自外部源(例如配置文件或数据库)的数据。

这比捕捉路线灵活得多,因为它可以让你动态选择控制器。

// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
    routes.Routes.Add(new MyRoute(
        innerRouter: routes.DefaultHandler)
    );

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

    // Uncomment the following line to add a route for porting Web API 2 controllers.
    // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});

用法

GetVirtualPath

RouteAsync应该反映RouteAsync的作用。 GetVirtualPath将URL转换为路由值,RedirectToAction应将相同的路由数据转换回相同的URL。

实现这一目标的最简单方法是使用数据结构在这两个数据点之间创建双向映射(如链接的答案中所示),这样您就不必在这两个数据点内不断更改逻辑方法。这个数据结构应该被缓存,而不是做太多资源密集的事情,因为每个请求都会使用它来确定每个URL的发送位置。

或者,您可以为每个逻辑逻辑创建单独的路径,并在应用程序启动时将它们全部注册。但是,您需要确保它们以正确的顺序注册,并且每条路由只匹配正确的URL集和正确的RouteValues集。

  

注意:对于此类情况,您几乎不需要使用/\S[,;:.?!]\S/ 。请记住,重定向会向浏览器发送HTTP 302请求,告知它查找服务器上的其他位置。在大多数情况下,这是不必要的开销,因为将初始请求路由到所需的控制器会更有效率。