我使用AutoMapper将我的域对象映射到我的视图模型。我在我的域层中有元数据,我想继承到视图层并进入ModelMetadata。 (这个元数据不是UI逻辑,而是为我的观点提供了必要的信息)。
现在,我的解决方案是使用单独的MetadataProvider(独立于ASP.NET MVC),并使用约定通过AssociatedMetadataProvider将相关元数据应用于ModelMetadata对象。这种方法的问题是,当我使用AutoMapping绑定模型元数据时,我必须测试相同的约定,并且似乎应该有一种方法使其更正确。任何人都可以推荐一个更好的方式来完成这个?
解决方法
我使用下面的方法自动将数据注释从我的实体复制到我的视图模型。这确保像StringLength和required值这样的实体对于entity / viewmodel始终是相同的。
它使用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); } }
验证器提供者
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); } }
辅导方法参考上述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; } } }
其他注释
>如果您使用依赖注入,请确保您的容器尚未替换内置元数据提供程序或验证程序提供程序。在我的情况下,我使用的是Ninject.MVC3包,它在创建内核后绑定了其中一个,然后我不得不重新绑定,所以我的类实际上被使用。我得到例外,只有被允许添加一次,花了大部分时间来跟踪它。