在重复的动态类型局部视图中从匿名类型 属性 发出 HTML 字符串

Emitting an HTML string from anonymous type property in a repeated, dynamically-typed Partial View

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

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

'object' does not contain a definition for 'MyField'

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

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

尝试过的解决方案

  1. 好吧,所以我假设我只是将我的 String 属性换成其中一个 IHtmlString 属性……不。因为我有匿名类型,Razor 引擎不知道 MyField 是一个 IHtmlString,并且(我假设)调用 .ToString(),然后像往常一样编码。

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

    'System.Web.Mvc.HtmlHelper' has no applicable method named 'DisplayFor' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

    哦,对了。动态调度——我不能在匿名方法上调用扩展方法,因为 Razor 不知道它们是什么。因为我使用 @model dynamic 明确地告诉它,绝地风格,“你不需要看到它的标识”。如果我总是知道它是什么类型,那么是的,我可以在不使用语法的情况下转换对象或调用扩展方法——但同样,dynamicanonymous。这里有点鸡生蛋还是蛋生鸡的问题。

我发现/编译了两个解决方案,但我对这两个都不满意。 YMMV:

  1. 在渲染每个 Partial View.

    之前在父 View 中设置 ViewBag.MyField

    好吧,我应该早点想出这个,但不得不提醒这种可能性 here 因为我很少使用它(尽可能使用强类型视图)。实际上我很早就尝试过这个,但是由于我多次渲染 Partial 的方式,它似乎并不合适。我实际上仍然不喜欢它,因为在父视图中,我必须在每次调用 @Html.Partial 之前不断更新 ViewBag.MyField (我的用例为 6 次)。这将 C# 代码 变量重用放置在我内容中间的页面下方,很容易遗漏并且难以维护。

  2. 使用反射:object myField = ((Type)Model.GetType()).GetProperty("MyField").GetValue(Model);

    这就是我最终决定用于我的用例的内容。尽管反射 wasn't intended for this scenario,尽管它需要一些额外的错误检查。维护它的人比 .NET MVC 更熟悉反射,它将代码合并到一个位置 - 在它重要的页面上,以及其余 "server-side" 操作的顶部。没有重复的电话或寻找参考。

    我实际上并不完全清楚为什么这有效(也适用于 dynamic 而不是 object),但我假设它与正在检查的 Razor 引擎有关myField 对象类型直接用于已知类型 (IHtmlString) 的特殊呈现,而不是看到未知的 object 并需要访问未知存在的 属性在编译时。