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)
其他说明