asp.net-mvc-3 - 使用 AutoMapper 将元数据传输到 View 模型的技术

标签 asp.net-mvc-3 asp.net-mvc-2 automapper modelmetadata modelmetadataprovider

我使用 AutoMapper 将我的域对象映射到我的 View 模型。我的域层中有元数据,我想将其转移到 View 层和 ModelMetadata。 (此元数据不是 UI 逻辑,而是为我的 View 提供必要的信息)。

现在,我的解决方案是使用单独的 MetadataProvider(独立于 ASP.NET MVC),并使用约定通过 AssociatedMetadataProvider 将相关元数据应用于 ModelMetadata 对象。这种方法的问题在于,在绑定(bind)域中的 ModelMetadata 时,我必须测试与使用 AutoMapping 时相同的约定,而且似乎应该有一种方法可以使这更加正交。谁能推荐一个更好的方法来完成这个?

最佳答案

我使用下面的方法自动将数据注释从我的实体复制到我的 View 模型。这确保了实体/ View 模型的 StringLength 和 Required 值总是相同的。

它使用 Automapper 配置工作,因此只要 AutoMapper 设置正确,如果 View 模型上的属性名称不同,它就可以工作。

您需要创建自定义 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;
        }
    }

}

其他说明
  • 如果您使用依赖注入(inject),请确保您的容器尚未替换内置的元数据提供程序或验证程序提供程序。在我的例子中,我使用的是 Ninject.MVC3 包,它在创建内核后绑定(bind)了其中一个包,然后我不得不在之后重新绑定(bind)它,以便实际使用我的类。我得到了关于只允许添加一次Required的异常(exception)情况,花了一天的大部分时间来追踪它。
  • 关于asp.net-mvc-3 - 使用 AutoMapper 将元数据传输到 View 模型的技术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9989785/

    相关文章:

    asp.net - 带有 MVC 3 的 MySql 连接器/网络

    c# - 响应 header 设置在 View 中消失 - asp net mvc

    asp.net-mvc-2 - ASP.MVC 验证成功总结

    .net - 将我的思维方式从 ASP.NET 迁移到 ASP.NET MVC 时需要了解哪些关键概念 (2)?

    c# - ASP.NET MVC - 使用 Automapper 进行映射

    c# - System.Web.Caching.Cache Dispose 对象是否从缓存中清除?

    jquery - 如何在验证事件上显示弹出窗口?

    c# - 学习如何处理高流量 asp.net mvc 站点的资源?

    c# - 使用 Automapper 映射对象列表

    c# - 寻找一个属性(装饰)来提及与自动映射器一起使用的源属性名称