使用 AutoMapper 将元数据传送到视图模型的技术 [英] Technique for carrying metadata to View Models with AutoMapper

查看:24
本文介绍了使用 AutoMapper 将元数据传送到视图模型的技术的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I use AutoMapper to map my domain objects to my view models. I have metadata in my domain layer, that I would like to carry over to the view layer and into ModelMetadata. (This metadata is not UI logic, but provides necessary information to my views).

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

Right now, my solution is to use a separate MetadataProvider (independently of ASP.NET MVC), and use conventions to apply the relevant metadata to the ModelMetadata object via an AssociatedMetadataProvider. The problem with this approach is that I have to test for the same conventions when binding the ModelMetadata from the domain as I do with my AutoMapping, and it seems like there should be a way to make this more orthogonal. Can anyone recommend a better way to accomplish this?

推荐答案

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

I use the approach below to automatically copy data annotations from my entities to my view model. This ensures that things like StringLength and Required values are always the same for entity/viewmodel.

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

It works using the Automapper configuration, so works if the properties are named differently on the viewmodel as long as AutoMapper is setup correctly.

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

You need to create a custom ModelValidatorProvider and custom ModelMetadataProvider to get this to work. My memory on why is a little foggy, but I believe it's so both server and client side validation work, as well as any other formatting you do based on the metadata (eg an asterix next to required fields).

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

Note: I have simplified my code slightly as I added it below, so there may be a few small issues.

元数据提供者

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个类中引用的Helper方法

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 包,它在创建内核后绑定了其中一个,然后我不得不重新绑定它,这样我的类就被实际使用了.我收到了关于仅允许添加一次 Required 的例外情况,花了一天的大部分时间来追踪它.

这篇关于使用 AutoMapper 将元数据传送到视图模型的技术的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆