C# 如何扩展DataAnnotationsModelMetadata
我有一个自定义的C# 如何扩展DataAnnotationsModelMetadata,c#,asp.net-mvc-4,razor,C#,Asp.net Mvc 4,Razor,我有一个自定义的DataAnnotationsModelMetadataProvider,我想返回一个从ModelMetadata派生的对象,以便在我的razor模板中有额外的属性 到目前为止,我的自定义提供程序仅覆盖CreateMetadata函数: protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object
DataAnnotationsModelMetadataProvider
,我想返回一个从ModelMetadata
派生的对象,以便在我的razor模板中有额外的属性
到目前为止,我的自定义提供程序仅覆盖CreateMetadata
函数:
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
ModelMetadataAttribute mma;
foreach (Attribute a in attributes)
{
mma = a as ModelMetadataAttribute;
if (mma != null)
mma.Process(modelMetadata);
}
return modelMetadata;
}
受保护的重写ModelMetadata CreateMatadata(IEnumerable)
但它所做的是复制属性,我想避免这种情况。
在这篇文章的最后一个答案中,有一些关于PopulateMetadata
的内容,但我在基本提供程序中找不到该函数…我建议您看看MvcExtensions
:
它的主要部分之一就是您正在做的事情—广泛的模型元数据配置/使用。您可能会在这里找到很多答案,或者干脆将其视为“随时可用”解决方案。经过思考,我实际上找到了一个不需要使用MvcExtensions
的解决方案,它将基类中包含的所有信息复制到派生类中
由于DataAnnotationsModelMetadata
及其基类除了初始化一些私有或受保护的值之外什么都不做,因此没有产生副作用的风险
public class ArtifyModelMetaDataProvider : DataAnnotationsModelMetadataProvider
{
private static List<Tuple<FieldInfo, FieldInfo>> _fieldsMap;
static ArtifyModelMetaDataProvider()
{
_fieldsMap = new List<Tuple<FieldInfo, FieldInfo>>();
foreach (FieldInfo customFI in GetAllFields(typeof(ArtifyModelMetadata)))
foreach (FieldInfo baseFI in GetAllFields(typeof(DataAnnotationsModelMetadata)))
if (customFI.Name == baseFI.Name)
_fieldsMap.Add(new Tuple<FieldInfo, FieldInfo>(customFI, baseFI));
}
private static List<FieldInfo> GetAllFields(Type t)
{
List<FieldInfo> res = new List<FieldInfo>();
while (t != null)
{
foreach (FieldInfo fi in t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
if (!fi.IsLiteral)
res.Add(fi);
t = t.BaseType;
}
return res;
}
private static void CopyToCustomMetadata(ModelMetadata baseMetadata, ArtifyModelMetadata customMetadata)
{
foreach (Tuple<FieldInfo, FieldInfo> t in _fieldsMap)
t.Item1.SetValue(customMetadata, t.Item2.GetValue(baseMetadata));
}
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
ArtifyModelMetadata modelMetadata = new ArtifyModelMetadata(this, containerType, modelAccessor, modelType, propertyName);
CopyToCustomMetadata(base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName), modelMetadata);
ModelMetadataAttribute mma;
Dictionary<string, string> htmlAttributes;
object tmp;
foreach (Attribute a in attributes)
{
mma = a as ModelMetadataAttribute;
if (mma != null)
{
mma.Process(modelMetadata);
htmlAttributes = mma.GetAdditionnalHtmlAttributes();
if (htmlAttributes != null)
{
foreach (KeyValuePair<string, string> p in htmlAttributes)
{
tmp = null;
tmp = modelMetadata.AdditionnalHtmlAttributes.TryGetValue(p.Key, out tmp);
if (tmp == null)
modelMetadata.AdditionnalHtmlAttributes.Add(p.Key, p.Value);
else
modelMetadata.AdditionnalHtmlAttributes[p.Key] = tmp.ToString() + " " + p.Value;
}
}
}
if (mma is TooltipAttribute)
modelMetadata.HasToolTip = true;
}
return modelMetadata;
}
}
public class ArtifyModelMetadata : DataAnnotationsModelMetadata
{
public bool HasToolTip { get; internal set; }
public Dictionary<string, object> AdditionnalHtmlAttributes { get; private set; }
public ArtifyModelMetadata(DataAnnotationsModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
: base(provider, containerType, modelAccessor, modelType, propertyName, null)
{
AdditionnalHtmlAttributes = new Dictionary<string, object>();
}
}
公共类artifiymodelMetadataProvider:DataAnnotationsModelMetadataProvider
{
私有静态列表_fieldsMap;
静态artifiymodelMetadataProvider()
{
_fieldsMap=新列表();
foreach(GetAllFields中的FieldInfo customFI(typeof(artifiymodelMetadata)))
foreach(GetAllFields中的FieldInfo baseFI(typeof(DataAnnotationsModelMetadata)))
if(customFI.Name==baseFI.Name)
_fieldsMap.Add(新元组(customFI,baseFI));
}
私有静态列表GetAllFields(类型t)
{
List res=新列表();
while(t!=null)
{
foreach(t.GetFields中的FieldInfo fi(BindingFlags.NonPublic | BindingFlags.Instance))
如果(!fi.IsLiteral)
决议增补(fi);
t=t.BaseType;
}
返回res;
}
私有静态void CopyToCustomMetadata(ModelMetadata-baseMetadata、artifiymodelmetadata-customMetadata)
{
foreach(Tuple t in_fieldsMap)
t、 Item1.SetValue(customMetadata,t.Item2.GetValue(baseMetadata));
}
受保护的重写ModelMetadata CreateMatadata(IEnumerable属性、类型containerType、Func modelAccessor、类型modelType、字符串propertyName)
{
ArtifyModelMetadata modelMetadata=新的ArtifyModelMetadata(this、containerType、modelAccessor、modelType、propertyName);
CopyToCustomMetadata(base.CreateMetadata(属性、containerType、modelAccessor、modelType、propertyName)、modelMetadata);
模型元数据属性mma;
辞典;颂词;
对象tmp;
foreach(属性中的属性a)
{
mma=a作为ModelMetadataAttribute;
如果(mma!=null)
{
mma.过程(模型元数据);
htmlAttributes=mma.GetAdditionnalHtmlAttributes();
如果(htmlAttributes!=null)
{
foreach(htmlAttributes中的KeyValuePair p)
{
tmp=null;
tmp=modelMetadata.AdditionnalHtmlAttributes.TryGetValue(p.Key,out-tmp);
if(tmp==null)
modelmatadata.AdditionnalHtmlAttributes.Add(p.Key,p.Value);
其他的
modelMetadata.AdditionnalHtmlAttributes[p.Key]=tmp.ToString()+“”+p.Value;
}
}
}
如果(mma是工具提示属性)
modelMetadata.HasToolTip=true;
}
返回模型元数据;
}
}
公共类ArtifyModelMetadata:DataAnnotationsModelMetadata
{
public bool HasToolTip{get;internal set;}
公共字典附加HtmlatAttributes{get;private set;}
公共ArtificModelMetadata(DataAnnotationsModelMetadataProvider提供程序、类型containerType、Func modelAccessor、类型modelType、字符串propertyName)
:base(提供程序、containerType、modelAccessor、modelType、propertyName、null)
{
AdditionnalHtmlatAttributes=新字典();
}
}
如果您想要一个通用解决方案在派生类中获得基类字段,并且您不能仅仅使用继承,因为您与我处于相同的情况,那么只需使用这个类:
public abstract class GenericBaseCopy<Src, Dst> where Dst : Src
{
private static List<Tuple<FieldInfo, FieldInfo>> _fieldsMap;
static GenericBaseCopy()
{
_fieldsMap = new List<Tuple<FieldInfo, FieldInfo>>();
foreach (FieldInfo customFI in GetAllFields(typeof(Dst)))
foreach (FieldInfo baseFI in GetAllFields(typeof(Src)))
if (customFI.Name == baseFI.Name)
_fieldsMap.Add(new Tuple<FieldInfo, FieldInfo>(customFI, baseFI));
}
private static List<FieldInfo> GetAllFields(Type t)
{
List<FieldInfo> res = new List<FieldInfo>();
while (t != null)
{
foreach (FieldInfo fi in t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
if (!fi.IsLiteral)
res.Add(fi);
t = t.BaseType;
}
return res;
}
public static void Copy(Src baseClassInstance, Dst dstClassInstance)
{
foreach (Tuple<FieldInfo, FieldInfo> t in _fieldsMap)
t.Item1.SetValue(dstClassInstance, t.Item2.GetValue(baseClassInstance));
}
}
公共抽象类GenericBaseCopy其中Dst:Src
{
私有静态列表_fieldsMap;
静态GenericBaseCopy()
{
_fieldsMap=新列表();
foreach(GetAllFields中的FieldInfo customFI(类型(Dst)))
foreach(GetAllFields中的FieldInfo baseFI(typeof(Src)))
if(customFI.Name==baseFI.Name)
_fieldsMap.Add(新元组(customFI,baseFI));
}
私有静态列表GetAllFields(类型t)
{
List res=新列表();
while(t!=null)
{
foreach(t.GetFields中的FieldInfo fi(BindingFlags.NonPublic | BindingFlags.Instance))
如果(!fi.IsLiteral)
决议增补(fi);
t=t.BaseType;
}
返回res;
}
公共静态无效副本(Src baseClassInstance、Dst dstClassInstance)
{
foreach(Tuple t in_fieldsMap)
t、 Item1.SetValue(dstClassInstance,t.Item2.GetValue(baseClassInstance));
}
}
+1谢谢!我会深入研究的。但是没有办法不用注入就能完成同样的事情吗?mvcextensions似乎非常强大,但有很多东西我不需要使用。这是否意味着我需要重构我所有的实际代码,以便它使用mvcextension而不是标准的mvc机制?@ppetrov mvcextensions需要用它的方法来管理你的HttpApplication,但是没有必要,你可以继续使用D