如何在MVC Core中动态选择控制器
我有一种情况,网站可能需要一个链接,根据数据库结果重定向到某些控制器。
例如:
site.com/abcd
需要从Item Controller返回结果,通常称为/ item / view / 123
这里的关键是我不能将abcd硬编码到路由中。 一些链接可能会转到项目控制器,其他链接可能会转到订单控制器。
我已经尝试了一个到控制器的catchall路由,然后加载所需的控制器,但环境没有设置,所以它不能正常工作(它找不到视图)。
您可以通过实现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
将URL转换为路由值, GetVirtualPath
应将相同的路由数据转换回相同的URL。
实现此目的的最简单方法是使用数据结构在这两个数据点之间创建双向映射(如链接的答案中所示),这样您就不必在这两种方法中不断更改逻辑。 这个数据结构应该被缓存,而不是做太多资源密集的事情,因为每个请求都会使用它来确定每个URL的发送位置。
或者,您可以为每个逻辑逻辑创建单独的路径,并在应用程序启动时将它们全部注册。 但是,您需要确保它们以正确的顺序注册,并且每条路由仅匹配正确的URL集和正确的RouteValues集。
注意:对于此类场景,您几乎不需要使用
RedirectToAction
。 请记住,重定向会向浏览器发送HTTP 302请求,告知它查找服务器上的其他位置。 在大多数情况下,这是不必要的开销,因为将初始请求路由到所需的控制器会更有效。
- ASP.NET 5 beta 8中的Windows身份validation支持
- ASP.NET 5中Global.json中项目部分的说明
- ASP.NET Core中的模型绑定将下划线映射到标题案例属性名称
- 在MVC6中如何阻止直接访问wwwroot中的文件夹?
- ASP.NET vNext – MissingMethodException:找不到方法:Microsoft.CodeAnalysis.Diagnostic> EmitResult.get_Diagnostics()’
- 如何在ASP.NET Core中将角色添加到Windows身份validation
- 如何关闭ASP.NET核心框架完成的日志记录
- 找不到Microsoft.AspNetCore.Antiforgery
- 视图组件中的Javascript