Asp.net mvc 如何注入自定义ModelMetadata属性并在Html帮助程序中使用它们
其思想(简化)是在字典中包含的ViewModel中具有用户可定义的属性。大致如下:Asp.net mvc 如何注入自定义ModelMetadata属性并在Html帮助程序中使用它们,asp.net-mvc,asp.net-mvc-3,metadata,Asp.net Mvc,Asp.net Mvc 3,Metadata,其思想(简化)是在字典中包含的ViewModel中具有用户可定义的属性。大致如下: public class MyViewModel { [Required] public string Name { get; set; } [DisplayName("User address")] public string Address { get; set; } // ... public IDictionary<string, string&
public class MyViewModel
{
[Required]
public string Name { get; set; }
[DisplayName("User address")]
public string Address { get; set; }
// ...
public IDictionary<string, string> MetaData { get; set; }
}
我还想使用这些附加属性:
Html.TextBox("PhoneNumber")
我的研究让我继承了DataAnnotationsModelMetadataProvider
(因为它还需要支持标准属性的标准DataAnnotations属性),并试图找出要覆盖的内容,以便将其他属性作为其他ModelMetadata元素注入,但我有点被卡住了
我走对了吗?这里还有什么可以帮我的吗
感谢另一种选择可能是构造一个类似于MVC 3中的ViewBag/ViewData的动态对象。您可以通过
Model.MetaData.Foo
访问一个对象,Foo
实际上会映射到字典中的一个键
支持ViewBag对象的类型为;这个类是内部的并且是密封的,所以您必须对它进行自定义实现(除非有更好的选项我不知道)。快速浏览一下MVC 3源代码,可以得出以下结论:
internal sealed class DynamicViewDataDictionary : DynamicObject {
private readonly Func<ViewDataDictionary> _viewDataThunk;
public DynamicViewDataDictionary(Func<ViewDataDictionary> viewDataThunk) {
_viewDataThunk = viewDataThunk;
}
private ViewDataDictionary ViewData {
get {
ViewDataDictionary viewData = _viewDataThunk();
Debug.Assert(viewData != null);
return viewData;
}
}
// Implementing this function improves the debugging experience as it provides the debugger with the list of all
// the properties currently defined on the object
public override IEnumerable<string> GetDynamicMemberNames() {
return ViewData.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
ViewData[binder.Name] = value;
// you can always set a key in the dictionary so return true
return true;
}
}
内部密封类DynamicViewDataDictionary:DynamicObject{
私有只读函数_viewDataThunk;
公共动态视图数据字典(Func viewDataThunk){
_viewDataThunk=viewDataThunk;
}
私有ViewDataDictionary ViewData{
得到{
ViewDataDictionary viewData=\u viewDataThunk();
Assert(viewData!=null);
返回视图数据;
}
}
//实现此函数可以改善调试体验,因为它为调试器提供了所有
//对象上当前定义的属性
公共重写IEnumerable GetDynamicMemberNames(){
返回ViewData.key;
}
公共重写bool TryGetMember(GetMemberBinder绑定器,输出对象结果){
结果=视图数据[binder.Name];
//由于ViewDataDictionary始终返回结果,即使键不存在,也始终返回true
返回true;
}
public override bool TrySetMember(SetMemberBinder绑定器,对象值){
ViewData[binder.Name]=值;
//您始终可以在字典中设置一个键,以便返回true
返回true;
}
}
与修改ModelMetadataProvider相比,此解决方案的一个可能优势是,您不必花费时间为您的场景构建所有自定义组件—默认的提供程序应该足够了。您确定要有一个字典,可以在其中抛出任何内容并基于此创建视图吗?在开始之前,我会重新思考这个问题。我想说的是,这样的解决方案往往以复杂的黑客行为而告终,变得无法维护。更不用说你将如何使用它执行绑定了——它可能需要另一个黑客程序。好吧,我同意你的观点,在一个定制的单个MVC项目中使用它将是维护的噩梦。问题是,这是打算用于我们定制的CMS,其中一个要求是具备上述功能。使用自定义模型活页夹时,绑定部件应该不会有问题。谢谢您的回答。我来看看在我们的例子中是否有类似的东西是可行的。为什么_viewDataThunk被定义为Func而不是ViewDataDictionary。这样做有什么好处?@JRoppert这是一个表演技巧。通过将对象包装在
Func
中,它可以有效地充当惰性加载程序。这样,所包含的ViewDataDictionary
在被使用之前不会执行。
internal sealed class DynamicViewDataDictionary : DynamicObject {
private readonly Func<ViewDataDictionary> _viewDataThunk;
public DynamicViewDataDictionary(Func<ViewDataDictionary> viewDataThunk) {
_viewDataThunk = viewDataThunk;
}
private ViewDataDictionary ViewData {
get {
ViewDataDictionary viewData = _viewDataThunk();
Debug.Assert(viewData != null);
return viewData;
}
}
// Implementing this function improves the debugging experience as it provides the debugger with the list of all
// the properties currently defined on the object
public override IEnumerable<string> GetDynamicMemberNames() {
return ViewData.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
ViewData[binder.Name] = value;
// you can always set a key in the dictionary so return true
return true;
}
}