EditorHelper是否使用ViewBag将数据传递到相应的模板?

时间:2013-12-11 08:52:28

标签: c# asp.net-mvc templates razor

我在覆盖Object.cshtm模板时发现了一种奇怪的行为。 Object.cshtm会迭代Model属性并将其“发送”到相应的模板进行渲染。

foreach (var prop in ViewData.ModelMetadata.Properties)        
{
    @Html.Editor(prop.PropertyName, 
          "MyCustomTemplateCollection" + prop.TemplateHint) 
    //TemplateHint set by custom attributes
}

一切正常:模板切换到相应的类型模板,在我可以访问的Metadata属性中:

string name = ViewData.ModelMetadata.PropertyName;
string controllerName = ViewData.ModelMetadata.ContainerType.Name;

//render property accordingly (using the property information)

但是,如果由于某种原因,ViewBag包含与Model属性之一同名的(动态)属性,则ModelMetadata未完全生成;至少上述ModelMetadata属性设置为null。例如,如果在我的控制器中设置了ViewBag.ProductName = myModel.ProductName;,当ProductName属性进入相应的模板时,元数据不包含“预期”值。

解决方案非常简单:如果由于某种原因,该属性需要保存在ViewBag中,则必须以不同的名称保存。

我的问题是:EditorHelper如何将数据传递给模板?我不希望ViewDataViewBag“分享”此类信息。使用 QuickWatch 进行检查我可以在Non-Public members ViewBag属性的ViewData中看到,该属性看起来与通常可用的ViewData相同1}}对象。为什么不完全独立?

1 个答案:

答案 0 :(得分:1)

你的问题有一个非常简单的答案:

ViewBagViewData的动态包装器。它们实际上是相同的东西。您放入ViewData的任何内容也在ViewBag中,反之亦然。

您可以看到DynamicViewDataDictionary的实现(ViewBaghere的实例){{3}}。正如您所看到的,它只是包含对它包装的ViewDataDictionary的内部引用,并将属性访问委托给字典元素。

因此,当框架将ViewData传递给具有特定键的模板并为您分配具有匹配名称的ViewBag属性时,只有一个可以获胜。

硬币的另一面 - 我认为实际上更相关 - 是事实上,负责提供元数据检查的静态ModelMetadata方法ViewData 首先检查模型对象的元数据。

因此,如果您将属性分配给ViewBag(以及 - 通过关联 - ViewData),则这些属性将与您传递给模板的表达式匹配,并且这些属性会赢得' t具有某些元数据,例如模型类上的数据注释所提供的元数据。