Asp.net mvc 4 在重复的、动态类型化的局部视图中从匿名类型属性发出HTML字符串

Asp.net mvc 4 在重复的、动态类型化的局部视图中从匿名类型属性发出HTML字符串,asp.net-mvc-4,razor,anonymous-types,asp.net-mvc-partialview,razorengine,Asp.net Mvc 4,Razor,Anonymous Types,Asp.net Mvc Partialview,Razorengine,我将匿名类型作为@model的一部分传递到动态局部视图中,其中一个属性是包含一些HTML的字符串。当我使用HtmlHelper方法呈现属性时,Razor引擎正在对字符串进行编码,在本例中,生成页面上的文本-text,而不是所需的text 因为它是一个动态类型的视图,所以我不能直接调用该属性。具体来说,如果我尝试绑定到@Model.MyField,我会得到一个RuntimeBindingException: 'object' does not contain a definition for 'M

我将匿名类型作为
@model
的一部分传递到动态局部视图中,其中一个属性是包含一些HTML的字符串。当我使用
HtmlHelper
方法呈现属性时,Razor引擎正在对字符串进行编码,在本例中,生成页面上的文本-
text
,而不是所需的
text

因为它是一个动态类型的视图,所以我不能直接调用该属性。具体来说,如果我尝试绑定到
@Model.MyField
,我会得到一个
RuntimeBindingException

'object' does not contain a definition for 'MyField'
理想情况下,我可以创建一个类型(或至少是一个接口)来指定视图(我建议将其作为最佳解决方案),但我的工作范围不允许这样做。另外,我首先使用的是
局部视图
,这样我就可以为不同的类型回收模板,这些类型具有相同的属性名称,但这些属性的类型不同(耶,遗留代码!)

我已经研究了几个解决类似问题的相关问题,但答案并不适用于我的具体情况(因为需要将匿名类型传递给我的
@model dynamic
视图)

    • 列出了几种失败的方法,决定通过
      @(新HtmlString(stringWithMarkup))
      MvcHtmlString.Create(stringWithMarkup)
    • 两者都需要已知类型或局部变量,并且不适用于绑定匿名
      对象的属性
    • 接受的答案有助于解释发生了什么: Razor中helpers和其他元素的所有输出都通过HttpUtility.HtmlEncode进行,除非它们实现了
      IHtmlString

尝试的解决方案
  • 好的,我假设我将把我的
    字符串
    属性换成其中一个
    IHtmlString
    属性。。。不。由于我有匿名类型,Razor引擎不知道
    MyField
    IHtmlString
    ,并且(我假设)调用
    .ToString()
    ,然后像往常一样对其进行编码

  • 好吧,也许
    @Html.DisplayFor
    更聪明?是,但访问被拒绝:

    “System.Web.Mvc.HtmlHelper”没有名为“DisplayFor”的适用方法,但似乎有一个同名的扩展方法。无法动态调度扩展方法。考虑在不使用扩展方法语法的情况下强制转换动态参数或调用扩展方法。 哦,对了。动态调度-我不能对匿名方法调用扩展方法,因为Razor不知道它们是什么。因为我使用了
    @model dynamic
    来明确地告诉它,绝地风格,“你不需要看到它的标识”。如果我总是知道它是什么类型的,那么是的,我可以强制转换对象或调用扩展方法,而不使用语法-但是再次强调,
    dynamic
    anonymous
    。这里有点鸡和蛋的问题


  • 我找到/汇编了两个解决方案,但我对这两个都不满意。YMMV:

  • 在呈现每个
    局部视图之前,在父视图
    视图中设置
    ViewBag.MyField

    好吧,我本应该早一点弄明白这一点的,但我必须记住这种可能性,因为我很少使用它(只要有可能,我更喜欢强类型视图)。事实上我很早就试过了,但由于我多次渲染部分的方式,它似乎不合适。实际上,我仍然不喜欢它,因为在父视图中,我必须在每次调用
    @Html.Partial
    (我的用例6次)之前不断更新
    ViewBag.MyField
    。这将C代码和变量重用方法放在我的内容中间的页面上,容易丢失和难以维护。

  • 使用反射:
    对象myField=((Type)Model.GetType()).GetProperty(“myField”).GetValue(Model)

    这就是我最终决定使用的用例。即使反射,即使它需要一点额外的错误检查。维护此功能的人员比.NETMVC更熟悉反射,并且它将代码整合到一个位置—在与之相关的页面上,并与其他“服务器端”操作一起位于顶部。没有重复呼叫或查找参考资料

    事实上,我并不完全清楚为什么这样做(也适用于
    动态
    而不是
    对象
    ),但我假设这与Razor引擎直接检查
    myField
    对象类型以进行已知类型的特殊渲染(
    IHtmlString
    )有关,而不是看到未知的
    对象
    ,需要访问编译时未知存在的属性

  • 详细介绍了为什么匿名类型和扩展方法不能混合使用。忘了我已经在一篇文章中链接到了这一点,但没有提到HTML编码。