代码之家  ›  专栏  ›  技术社区  ›  Slava Knyazev

从MVC路由器的虚拟路径中检索路由数据

  •  1
  • Slava Knyazev  · 技术社区  · 7 年前

    我正在开发一个.NET核心MVC应用程序,它要求允许使用其他控制器/操作名称。为此,我在MapRoute上使用自己的路由器:

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

    我的自定义路由器观察请求的控制器和操作,并基于它将一个新值放入请求中的routeddata中:

    public async Task RouteAsync(RouteContext context)
    {
       [...]
       if (requestedAction == "fakeAction")
        context.RouteData.Values["action"] = "realAction";
    

    但是,要确定 requestedAction ,我基本上是采用请求的路径,将其拆分并以这种方式获取其值。这似乎不太理想。

    var rr = new RouteBuilder(app);
    var myRoute = rr.MapRoute(...).Build();
    var myRouteData = myRoute.GetRouteData(context);
    myRouteData["action"] == "fakeAction";
    

    我非常喜欢的另一个解决方案是,如果我能做到以下几点:

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

    something route实际上路由任何东西,并且只作为为我的CustomRouter定义RouteData的一种方式。

    这两个都可能吗?我不喜欢我们不干净地实现现有功能的想法,因为这既是一种代码味道,也是未来潜在的维护困难。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Hossein    7 年前

    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);
        }
    
        // Get the page that matches.
        var page = GetPageList()
            .Where(x => x.VirtualPath.Equals(requestPath))
            .FirstOrDefault();
    
        // If we got back a null value set, that means the URI did not match
        if (page == null)
        {
            return;
        }
    
    
        //Invoke MVC controller/action
        var oldRouteData = context.RouteData;
        var newRouteData = new RouteData(oldRouteData);
        newRouteData.Routers.Add(this.target);
    
        // TODO: You might want to use the page object (from the database) to
        // get both the controller and action, and possibly even an area.
        // Alternatively, you could create a route for each table and hard-code
        // this information.
     if (context.RouteData.Values["action"] == "fakeAction")
        newRouteData.Values["controller"] = "realController";
        newRouteData.Values["action"] = "realAction";
    
        // This will be the primary key of the database row.
        // It might be an integer or a GUID.
        newRouteData.Values["id"] = page.Id;
    
        try
        {
            context.RouteData = newRouteData;
            await this.target.RouteAsync(context);
        }
        finally
        {
            // Restore the original values to prevent polluting the route data.
            if (!context.IsHandled)
            {
                context.RouteData = oldRouteData;
            }
        }
    }
    
    app.UseMvc(routes =>
    {
        routes.Routes.Add(
           new CustomRoute(routes.ServiceProvider.GetRequiredService<IMemoryCache>(), 
                           routes.DefaultHandler));
    
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    
    
    });