Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何扩展DataAnnotationsModelMetadata_C#_Asp.net Mvc 4_Razor - Fatal编程技术网

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