答案 0 :(得分:1)
首先,我建议您使用字典作为viewModel。这允许您添加您喜欢的任何属性(名称/值)。
其次,为了满足安全性要求,我将a)对用户进行身份验证(Forms / Windows),并b)创建一些查询数据库的功能,以查看用户被允许提交/编辑/查看的对象如何。查询的结果可能只是一个包含允许字段名称的字符串数组 - 这是您的元数据。使用此数据,您可以轻松删除未经授权的值。 ModelBinder就是这样做的地方。
第三,对于验证,您可以通过将字符串数组替换为Touple(Of string,bool)列表来扩展METADATA,其中存储一个布尔值,指示该值是否为必需的用户输入。您仍然可以通过实现A MetaDataProvider来依赖ASP.NET MVC默认值。这可能是一个启动者:http://buildstarted.com/2010/09/14/creating-your-own-modelmetadataprovider-to-handle-custom-attributes/
最后,DisplayTemplates和EditorTemplates可以轻松驱动动态UI。为常用数据类型创建模板,为Dictionary创建模板。最后一个只是迭代它的KeyValuePairs写标签并调用具体的数据类型模板。 同样,METADATA可以使用MetaDataProvider扩展并提供给ASP.NET MVC。
- 丹尼尔
答案 1 :(得分:-1)
发布一个接受的答案,因为我找到了我自己需要的解决方案,虽然我还剩下一部分,如果我需要额外的帮助而不是留下这个问题,我会将其作为一个单独的问题发布。有关详细信息,请参阅我的原始帖子。
向下投票是一个很好的提醒,回到这里,所以你在这里: - )
好的,所以这就是我最后的实施方式。希望这可以帮助你们中的一些人了解自己的情况。我必须透露我正在给予 Works on my Machine 批准印章,您应该自己测试一下,看它是否符合您的需求。做出某些决定是为了遵守现有的数据/做法。如果您遇到任何有关此代码的问题,请随时回复此帖子,以便其他人可以受益。为了简洁,我会尝试缩短代码,因为某些细节属于我的雇主。这是它的主旨,因为它与MVC有关。
注意:我目前正在使用MVC4,但这也适用于MVC3。虚拟修饰符适用于nHibernate
<强>波苏斯强>
public class PseudoObject
{
// Other properties and such...
public virtual IList<PseudoObjectAttribute> Attributes { get; set; }
// Other methods, etc...
}
public class PseudoObjectAttribute
{
// Other properties and such...
public virtual string Value { get; set; }
//This holds all of the info I need for determine metadata & validation
public virtual PseudoObjectStructure Structure { get; set; }
// Other methods, etc...
}
public class PseudoObjectStructure
{
public virtual bool IsRequired { get; set; }
public virtual string RegularExpression { get; set; }
public virtual string RegularExpressionErrorMessage { get; set; }
}
<强> MetadataProvider 强>
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
//We only care about providing custom model metadata to PseudoObjectAttribute objects
if ((containerType != typeof(PseudoObjectAttribute) && modelType != typeof(PseudoObjectAttribute)) || modelAccessor == null)
return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
ModelMetadata metadata = null;
PseudoObjectAttribute attributeViewModel = null;
System.Reflection.FieldInfo container = null;
//The contents of this if statement allows me to get the PseudoObjectAttribute instance I need to work with.
//This happens when we want metadata for the PseudoObjectAttribute type as a whole, not a specific attribute
if (modelType == typeof(PseudoObjectAttribute) && containerType == null)
{
//
if (modelAccessor.Target is ViewDataDictionary)
attributeViewModel = (PseudoObjectAttribute)((ViewDataDictionary)modelAccessor.Target).Model;
else
{
container = modelAccessor.Target.GetType().GetField("item");
if (container != null)
{
attributeViewModel = (PseudoObjectAttribute)container.GetValue(modelAccessor.Target);
}
container = modelAccessor.Target.GetType().GetField("model");
if (container != null)
attributeViewModel = (PseudoObjectAttribute)container.GetValue(modelAccessor.Target);
}
}
else if(!string.IsNullOrEmpty(propertyName))
{
if (modelAccessor.Method.Name.Contains("FromStringExpression"))
{
//This happens when we want metadata for a specific property on the PseudoObjectAttribute
container = modelAccessor.Target.GetType().GetField("vdi");
attributeViewModel = (PseudoObjectAttribute)((System.Web.Mvc.ViewDataInfo)container.GetValue(modelAccessor.Target)).Container;
}
//GetPropertyValueAccessor is used when you bind the posted back form
else if (modelAccessor.Method.Name.Contains("FromLambdaExpression") || modelAccessor.Method.Name.Contains("GetPropertyValueAccessor"))
{
//Accessed property via lambda
container = modelAccessor.Target.GetType().GetField("container");
var accessor = container.GetValue(modelAccessor.Target);
//Sometimes the property is access straight from the parent object for display purposes in the view ex. someRegistration["ProductId"].GuidValue
//In these situations the access is the Registration object and is not something we can use to derive the attribute.
if (accessor is PseudoObjectAttribute)
attributeViewModel = (PseudoObjectAttribute)accessor;
}
}
// At this point I have an instance of the actual PseudoObjectAttribute object I'm trying to derive Metadata for and can build my Metadata easily using it.
// I'm using typeof (String) as a starting point to build my custom metadata from but it could be any value type if you wanted to befit from the defaults
metadata = new ModelMetadata(this, typeof (PseudoObjectAttribute), modelAccessor, typeof (String), propertyName);
// Be sure to store any of the information you've obtained here that is needed to derive validation rules in the AdditionalValues
metadata.AdditionalValues.Add("Structure", attributeViewModel.Structure);
//TODO: Populate the rest of the Metadata here....
return metadata;
}
<强> ValidatorProvider 强>
public class PseudoObjectAttributeValidatorProvider : ModelValidatorProvider
{
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata.ContainerType == typeof(PseudoObjectAttribute) && metadata.PropertyName == "StringValue")
{
PseudoObjectStructure structure = null;
try
{
if (metadata.AdditionalValues.Any())
structure = (PseudoObjectStructure)metadata.AdditionalValues["Structure"];
}
catch (KeyNotFoundException) { }
if (structure != null)
{
if (structure.IsRequired)
yield return new RequiredAttributeAdapter(metadata, context, new RequiredAttribute());
if (structure.RegularExpression != null)
yield return new RegularExpressionAttributeAdapter(metadata, context, new RegularExpressionAttribute(structure.RegularExpression) { ErrorMessage = structure.RegularExpressionErrorMessage });
}
}
else
yield break;
}
}
我认为这就是一切。如果我错过了什么让我知道。