【问题标题】:How Can I Reconstruct URL/Route in ASP.NET MVC From Saved Data?如何从保存的数据重建 ASP.NET MVC 中的 URL/路由?
【发布时间】:2009-05-05 16:03:16
【问题描述】:

我对 ASP.NET MVC 框架及其管道的不熟悉将我带到这里,我感谢任何人阅读和考虑我的问题所需要的耐心!

好的,这是场景:我有一个应用程序,它有许多带有网格的页面,这些页面显示基于搜索的数据、从其他数据向下钻取、基于上下文特定数据的报告(即它们位于 Foo 的详细信息页面上,然后单击显示与 Foo 相关的数据表的链接)等。

从应用程序各处的所有这些页面中,用户可以通过为其命名和描述来保存“报告”或网格。这并没有真正保存显示在网格中的数据,而是保存定义网格外观的参数,保存用于获取数据的参数,并保存参数定义它们在应用程序中的“位置”(动作、控制器、路由)——基本上是一堆关于报告/网格以及如何构建它的元数据。

所有这些保存的报告都在一个列表中可用,在应用程序的某个页面上显示名称和描述,每个链接到一个通用 URL,例如“/Reports/Saved/248”(其中 248 是报告 ID 的示例)。

这是我需要帮助的部分:

当我通过 url “/Reports/Saved/248” 获取操作并将元数据从该特定报告的数据库中拉出时,我如何将该数据和请求重定向到相同的操作、控制器和路由用于显示最初保存报告的视图?本质上,我希望用户在同一个视图中查看报表,并使用与保存报表相同的 URL。如果可能的话,如果我能够基本上“调用”相同的操作,就好像我在进行方法调用一样,这将是一件好事。


更新:不幸的是,我们的报告页面(即这些网格出现的页面)没有使用 RESTful URL - 例如,我们有我们所谓的高级搜索页面,它需要相当多的潜在参数(近 30 ) 来自包含选择列表、文本框等的表单。当用户提交该页面时,我们对接受模型绑定器为我们构建的复杂类型的操作执行 POST - 同样的操作是我想要调用的当用户从数据库中选择保存的高级搜索时。这个例子体现了我的问题。

谢谢

【问题讨论】:

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


    【解决方案1】:

    我认为您会希望将 RedirectToAction 与采用 RouteValueDictionary 的签名一起使用。您要重定向到的方法需要能够从控制器上的 ValueProvider 中提取值。它可能看起来像:

    public ActionResult Saved( int id )
    {
        var reportParams = db.Reports.SingleOrDefault( r => r.ID == id );
        if (reportParams == null)
           ...handle error...
    
        var routeValues = ParamsToRouteValueDictionary( reportParams );
    
        return RedirectToAction( reportParams.Action, reportParams.Controller, routeValues );
    }
    
    private RouteValueDictionary ParamsToRouteValueDictionary( object parameters )
    {
         var values = new RouteValueDictionary();
         var properties = parameters.GetType().GetProperties()
                                    .Where( p => p.Name != "Action" && p.Name != "Controller" );
         foreach (var prop in properties)
         {
             values.Add( prop.Name, prop.GetValue(parameters,null) );
         }
    
         return values;
    }
    

    编辑

    使用过滤器模型作为方法的参数实际上可能会更容易。您只需要操作的 GET 和 POST 版本。

     [ActionName("People")]
     [AcceptVerbs( HttpVerbs.Get )]
     public ActionResult PeopleDisplay( SearchModel filter )
     {
         return People( filter );
     }
    
     [AcceptVerbs( HttpVerbs.Post)]
     [ValidateAntiForgeryToken]
     public ActionResult People( SearchModel filter )
     {
         ....
     }
    

    然后,您可以将过滤器参数(按名称)、操作(“人员”)和控制器存储在您的报告数据库中。重定向结果将使用 GET 并被定向到 PeopleDisplay 方法,该方法又简单地使用正确的参数调用 People 方法。从表单发布直接调用 People 方法。使用两种方法可以让您使用 CSRF 预防机制。您也许可以在 TempData 中使用一个标志来确保只有在您希望限制对它的访问时才通过重定向机制调用 GET 操作。

    结束编辑

    另一种选择是简单地存储使用的视图,而不是进行重定向,只需渲染适当的视图。您需要考虑的一件事是,执行重定向最终会得到一个包含所有参数的 URL,而呈现视图将不理会 URL,只显示与创建报告时使用的 URL 相同的视图.

    【讨论】:

    • 感谢您的回复,请查看我的问题的更新。
    • 我认为 ModelBinder 可以毫无区别地使用路由参数或表单参数——因为它使用了 ValueProvider。您需要做的唯一想法是确保您的操作可以接受 GET 或 POST。我会更新一个示例。
    • 好的,谢谢您的回复 - 我很快就能测试出来。感谢您的宝贵时间!
    • 幸运的是,我们做了一些完全不同的事情,但这是最好的答案,你花了额外的时间回来回复我的编辑,所以我将其标记为答案。再次感谢!
    • 我很好奇 Jason 您选择了哪种解决方案?如果您可以将其作为另一个答案发布在这里,它可能对像我这样通过谷歌登陆这里的人有所帮助。 :-)
    【解决方案2】:

    您可以使用 RedirectToAction 方法发出 301 重定向到任何控制器上的特定操作方法,以及路由值:

    ReportMeta meta = _reportDataAccess.Get(id);
    return RedirectToAction(meta.Action, meta.Controller, meta.RouteData);
    

    这些值类似于:

    meta.Action = "Bar";
    meta.Controller = "Foo";
    meta.RouteData = new {
        // possibly settings for the grid
        start = DateTime.Min,
        end = DateTime.Now,
        sort = "Date"
        // you get the idea
    };
    

    当然,我可以看到的直接问题是当您的控制器/操作方法随时间变化时会发生什么,报告数据将无效。但是你可能已经想到了。

    【讨论】:

    • 感谢您的回复,请查看我的问题的更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-19
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 2010-11-13
    相关资源
    最近更新 更多