【问题标题】:In an MVC5 controller how do I create an IDictionary or routeValueDictionary for an HtmlHelper's htmlAttributes or routeValues?在 MVC5 控制器中,如何为 HtmlHelper 的 htmlAttributes 或 routeValues 创建 IDictionary 或 routeValueDictionary?
【发布时间】:2020-06-03 02:57:47
【问题描述】:

MVC5

最终目标是在控制器中创建视图链接,因为它们会根据程序逻辑而变化。

以下链接编译运行:

Dim myLink = HtmlHelper.GenerateLink(Request.RequestContext, RouteTable.Routes, "edit", "Default", "Edit", "Role", Nothing, Nothing)

上面的行生成:<a href=""/Role/Edit"">edit</a>。然后使用 html.raw 在视图中显示,并生成链接:http://localhost:53908/Role/Edit

上面显示的链接导航正确,但不能使用action方法,因为我需要传递一个ID参数,所以我尝试将帮助程序中的最后一个参数更改如下:

Dim myLink = HtmlHelper.GenerateLink(Request.RequestContext, RouteTable.Routes, "edit", "Default", "Edit", "Role", Nothing, New With {.ID = "somedata"})

但上面一行返回语法警告,代码无法运行:

Runtime errors might occur when converting '<anonymous type: ID As String>' to 'IDictionary(Of String, Object)'

然后我尝试创建一个 IDictionary,如下所示:

Dim temp As IDictionary(Of String, String)
temp.Add("ID", "somedata")
Dim myLink = HtmlHelper.GenerateLink(Request.RequestContext, RouteTable.Routes, "edit", "Default", "Edit", "Role", Nothing, temp)

上面的代码满足 HtmlHelper,但是 temp.Add 行不起作用,因为:

temp is used before it has been assigned a value.

运行时发生空引用异常。我对 IDictionary 不是特别熟悉,也不知道下一步该做什么。

所以我有一系列问题:

  1. 有没有办法通过调用助手来创建助手“即时”要求的IDictionary
  2. 我应该以不同的方式使用HtmlHelper.GenerateLink 方法吗?
  3. 如何创建IDictionary

在原帖之后添加:

最初的问题涉及创建一个就地 IDictionary 以在 Controller 中使用 HtmlHelpers,以便可以在代码中而不是在视图中完成创建链接。总体意图是让 Controller 代码执行必要的逻辑并计算链接,而不是在视图中进行。

最初提出的问题涉及 htmlAttributes 是偶然的,因为在这种特殊情况下,真正需要的是创建 routeValues。但下面的答案实际上有助于告知如何做到这两点。

成功的关键是使用正确的关键字。在创建 New RouteValueDictionary 或 New IDictionary 的情况下,必须使用 New Dictionary(Of String, Object),这意味着关键字 Object 是必需的,而关键字 From 是就地设置所必需的记录定义。在 MVC5 中,语法 New Dictionary(Of String, String) 被视为匿名类型,不能就地或其他方式转换为 IDictionary。

根据下面的答案,在控制器中用于在视图中设置等效 ActionLink 的最终代码是:

Dim editLink = HtmlHelper.GenerateLink(Request.RequestContext,
    RouteTable.Routes,
    "Edit",      'the link text
    "Default",   'a route name, can found in RouteConfig.vb
    "Edit",      'the target ActionResult method
    "Role",      'the target Controller
    New RouteValueDictionary(New Dictionary(Of String, Object) From {"ID", role.Id}, {"selectedDomain", selectedDomain}}),
    Nothing)

在上述情况下,ActionResult 方法根据需要向 routeValueDictionary 添加了第二个路由值。

如果还需要 htmlAttributes,可以添加它们来代替上面显示的最终 Nothing,如下面的答案中所述。

【问题讨论】:

    标签: vb.net razor asp.net-mvc-5 html-helper


    【解决方案1】:

    参数类型为IDictionary(Of String, Object)。那只是一个接口,因此您需要创建一个实现该接口的类型的对象。显而易见的选择是Dictionary(Of String, Object),例如

    Dim temp As IDictionary(Of String, Object) = New Dictionary(Of String, Object)
    temp.Add("ID", "somedata")
    Dim myLink = HtmlHelper.GenerateLink(Request.RequestContext, RouteTable.Routes, "edit", "Default", "Edit", "Role", Nothing, temp)
    

    我不记得在这种情况下何时开始支持匿名类型,但它似乎晚于 MVC 5。如果您希望能够使用匿名类型,那么您必须编写自己的方法来接受匿名类型,使用反射从中提取数据,构建字典,然后调用现有方法。你可以这样做:

    Public Module HtmlHelperExtender
    
        Public Function GenerateLink(requestContext As RequestContext,
                                     routeCollection As RouteCollection,
                                     linkText As String,
                                     routeName As String,
                                     actionName As String,
                                     controllerName As String,
                                     routeValues As RouteValueDictionary,
                                     htmlAttributes As Object) As String
            'Create a dictionary from the properties of the anonymously typed object.
            Dim attributesType = htmlAttributes.GetType()
            Dim properties = attributesType.GetProperties()
            Dim htmlAttributesDictionary = properties.ToDictionary(Function(p) p.Name, Function(p) p.GetValue(htmlAttributes))
    
            Return HtmlHelper.GenerateLink(requestContext,
                                           routeCollection,
                                           linkText,
                                           routeName,
                                           actionName,
                                           controllerName,
                                           routeValues,
                                           htmlAttributesDictionary)
        End Function
    
    End Module
    

    然后您可以像最初尝试的那样调用该方法:

    Dim myLink = HtmlHelperExtender.GenerateLink(Request.RequestContext,
                                                 RouteTable.Routes,
                                                 "edit",
                                                 "Default",
                                                 "Edit",
                                                 "Role",
                                                 Nothing,
                                                 New With {.ID = "somedata"})
    

    我刚刚想到的另一个选择是坚持使用字典,但在原地创建和填充它,这可以使用 From 关键字:

    Dim myLink = HtmlHelper.GenerateLink(Request.RequestContext,
                                         RouteTable.Routes,
                                         "edit",
                                         "Default",
                                         "Edit",
                                         "Role",
                                         Nothing,
                                         New Dictionary(Of String, Object) From {{"ID", "somedata"}})
    

    【讨论】:

    • 一如既往,您给出了很好的答案,谢谢!你回答了我的问题,我使用你的最后一个代码部分就地创建了字典。我在这方面学到了很多。但是,有一个问题。我的问题是关于 htmlAttributes,但我很快发现它确实需要关于 routeValues。因此,我对 routeValues 参数使用了相同的就地解决方案,效果很好。我还没有做 HtmlHelperExtender 但会。问题:我应该在帖子更新的末尾添加一个部分来更新 routeValues 吗?
    • 你是说最后两个参数不是Nothing, New Dictionary(Of String, Object) From {{"ID", "somedata"}},而是New RouteValueDictionary From {{"ID", "somedata"}}, Nothing?如果是这样,那么也许您应该在问题的末尾添加一个编辑,我将在答案的末尾添加相应的编辑。编辑标题以表明它同时处理两个参数可能也是值得的。
    • 你是对的,我更新了原帖和标题。再次感谢。你帮了我很多。干杯,然后……。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-10
    相关资源
    最近更新 更多