我在覆盖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
如何将数据传递给模板?我不希望ViewData
和ViewBag
“分享”此类信息。使用 QuickWatch 进行检查我可以在Non-Public members
ViewBag
属性的ViewData
中看到,该属性看起来与通常可用的ViewData
相同1}}对象。为什么不完全独立?
答案 0 :(得分:1)
你的问题有一个非常简单的答案:
ViewBag
是ViewData
的动态包装器。它们实际上是相同的东西。您放入ViewData
的任何内容也在ViewBag
中,反之亦然。
您可以看到DynamicViewDataDictionary
的实现(ViewBag
是here的实例){{3}}。正如您所看到的,它只是包含对它包装的ViewDataDictionary
的内部引用,并将属性访问委托给字典元素。
因此,当框架将ViewData
传递给具有特定键的模板并为您分配具有匹配名称的ViewBag
属性时,只有一个可以获胜。
硬币的另一面 - 我认为实际上更相关 - 是事实上,负责提供元数据检查的静态ModelMetadata
方法ViewData
首先检查模型对象的元数据。
因此,如果您将属性分配给ViewBag
(以及 - 通过关联 - ViewData
),则这些属性将与您传递给模板的表达式匹配,并且这些属性会赢得' t具有某些元数据,例如模型类上的数据注释所提供的元数据。