使用AutoMapper将元数据传送到View模型的技术

sma*_*man 16 automapper modelmetadata modelmetadataprovider asp.net-mvc-3 asp.net-mvc-2

我使用AutoMapper将我的域对象映射到我的视图模型.我的域层中有元数据,我希望将其转移到视图层和ModelMetadata中.(此元数据不是UI逻辑,但为我的视图提供了必要的信息).

现在,我的解决方案是使用单独的MetadataProvider(独立于ASP.NET MVC),并使用约定通过AssociatedMetadataProvider将相关元数据应用于ModelMetadata对象.这种方法的问题在于,当我使用AutoMapping绑定ModelMetadata时,我必须测试相同的约定,似乎应该有一种方法可以使这更加正交.任何人都可以推荐更好的方法来实现这一目标

Bet*_*tty 14

我使用下面的方法自动将数据注释从我的实体复制到我的视图模型.这可确保实体/视图模型的StringLength和Required值之类的内容始终相同.

它使用Automapper配置,因此只要在正确设置AutoMapper的情况下在视图模型上以不同方式命名属性,它就可以工作.

您需要创建自定义ModelValidatorProvider和自定义ModelMetadataProvider才能使其正常工作.我对于为什么有点迷雾的记忆,但我相信服务器和客户端验证都是如此,以及基于元数据执行的任何其他格式化(例如,必需字段旁边的星号).

注意:我稍微简化了我的代码,因为我在下面添加了它,所以可能会有一些小问题.

元数据提供者

public class MetadataProvider : DataAnnotationsModelMetadataProvider
{        
    private IConfigurationProvider _mapper;

    public MetadataProvider(IConfigurationProvider mapper)
    {           
        _mapper = mapper;
    }

    protected override System.Web.Mvc.ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {           
        //Grab attributes from the entity columns and copy them to the view model
        var mappedAttributes = _mapper.GetMappedAttributes(containerType, propertyName, attributes);

        return base.CreateMetadata(mappedAttributes, containerType, modelAccessor, modelType, propertyName);

}
}
Run Code Online (Sandbox Code Playgroud)

Validator Provivder

public class ValidatorProvider : DataAnnotationsModelValidatorProvider
{
    private IConfigurationProvider _mapper;

    public ValidatorProvider(IConfigurationProvider mapper) 
    {
        _mapper = mapper;
    }

    protected override System.Collections.Generic.IEnumerable<ModelValidator> GetValidators(System.Web.Mvc.ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {   
        var mappedAttributes = _mapper.GetMappedAttributes(metadata.ContainerType, metadata.PropertyName, attributes);
        return base.GetValidators(metadata, context, mappedAttributes);
    }
}
Run Code Online (Sandbox Code Playgroud)

辅助方法参考上述2个类

public static IEnumerable<Attribute> GetMappedAttributes(this IConfigurationProvider mapper, Type sourceType, string propertyName, IEnumerable<Attribute> existingAttributes)
{
    if (sourceType != null)
    {
        foreach (var typeMap in mapper.GetAllTypeMaps().Where(i => i.SourceType == sourceType))
        {
            foreach (var propertyMap in typeMap.GetPropertyMaps())
            {
                if (propertyMap.IsIgnored() || propertyMap.SourceMember == null)
                    continue;

                if (propertyMap.SourceMember.Name == propertyName)
                {
                    foreach (ValidationAttribute attribute in propertyMap.DestinationProperty.GetCustomAttributes(typeof(ValidationAttribute), true))
                    {
                        if (!existingAttributes.Any(i => i.GetType() == attribute.GetType()))
                            yield return attribute;
                    }
                }
            }
        }
    }

    if (existingAttributes != null)
    {
        foreach (var attribute in existingAttributes)
        {
            yield return attribute;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

其他说明

  • 如果您正在使用依赖项注入,请确保您的容器尚未替换内置元数据提供程序或验证程序提供程序.在我的情况下,我使用Ninject.MVC3包,在创建内核后绑定其中一个,然后我不得不重新绑定它,所以我的类实际上被使用了.我得到了关于必需的例外,只允许添加一次,花了大部分时间来追踪它.