在 MVC5 控制器中,如何为 HtmlHelper 的 htmlAttributes 或 routeValues 创建 IDictionary 或 routeValueDictionary?

In an MVC5 controller how do I create an IDictionary or routeValueDictionary for an HtmlHelper's htmlAttributes or routeValues?

MVC5

最终objective是在控制器中创建视图的link,因为它们根据程序逻辑而改变。

以下 link 编译并 运行s:

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

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

上面显示的 link 导航正确,但不能与 action 方法一起使用,因为我需要传递一个 ID 参数,所以我尝试更改 helper 中的最后一个参数,如下所示:

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

但是上面那行 returns 是语法警告,代码不能 运行:

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. 有没有办法通过调用助手来创建助手 'on the fly' 要求的 IDictionary
  2. 我应该以不同的方式使用 HtmlHelper.GenerateLink 方法吗?
  3. 如何创建 IDictionary

在原post之后添加:

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

最初提出的问题无意中处理了 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 显示,如下面的答案中所指定。

参数类型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"}})