升级到 9 后无法访问自动映射器上下文项

问题描述 投票:0回答:4

我有一个这样的映射器:

CreateMap<Source, ICollection<Dest>>()
    .ConvertUsing((src, dst, context) => 
    {
        return context.Mapper.Map<ICollection<Dest>>
            (new SourceItem[] { src.Item1, src.Item2 ... }.Where(item => SomeFilter(item)),
            opts => opts.Items["SomethingFromSource"] = src.Something);
    });

CreateMap<SourceItem, Dest>()
    .ForMember(d => d.Something, opts => opts.MapFrom((src, dst, dstItem, context)
        => (string)context.Items["SomethingFromSource"]));

这给了我一个例外,说

You must use a Map overload that takes Action<IMappingOperationOptions>
。好吧,我确实使用了执行此操作的
Map
重载。我还能怎么做?

c# automapper
4个回答
21
投票

这是因为这个变化:
https://github.com/AutoMapper/AutoMapper/pull/3150

您可以通过访问ResolutionContext的Options属性来获取项目。

context.Items["SomethingFromSource"]
更改为
context.Options.Items["SomethingFromSource"]

没有 Item 时,

ResolutionContext
DefaultContext
相同。因此
ResolutionContext.Items
属性将抛出异常。
然而,如果有的话,
ResolutionContext.Items
就不会与
DefaultContext
相同。因此
ResolutionContext.Items
将返回列表。

虽然

ResolutionContext.Options.Items
总是返回列表,但它不会抛出任何异常,无论它是否为空。我相信这就是错误消息的含义,因为
ResolutionContext.Options
IMappingOperationOptions


编辑于 2023 年 8 月 21 日:以上是在 AutoMapper 12 之前编写的。对于 12 及更高版本,请参阅下面的@Pieter Riesz 回答。感谢@Stoyan Dimov 和@Peter Riesz 的更新。


3
投票

v12.0.0之前

您可以通过访问ResolutionContext的

Options
属性来获取项目。

 => context.Options.Items["SomethingFromSource"]

v12.0.0

在12.0.0版本中,

Options
已被删除,您需要升级。

v12.0.1

如果您想检查

TryGetItems
调用中是否传递了上下文,可以使用
Map

 => context.TryGetItems(out var items) ? (string)items["SomethingFromSource"] : null

https://docs.automapper.org/en/latest/12.0-Upgrade-Guide.html


2
投票

此扩展可以帮助迁移到 AutoMapper 12

public static class AutoMapperExtensions
{
    public static TDestination MapOptions<TDestination>(this IMapper mapper, object source, Action<IMappingOperationOptions<object, TDestination>> OptionalOptions = null)
    {
        return mapper.Map(source, OptionalOptions ?? (_ => {}) );
    }
}

在已注入 IMapper 的类中

public class Command
{
    protected readonly IMapper AutoMapper;

    public Command(IMapper mapper)
    {
        AutoMapper = mapper;
    }

    private SomethingToDo()
    {
        var list = new List<string>();
        // change for 12
        var result = AutoMapper.MapOptions<IList<Item>>(list);
        // prior to 12
        //var result = AutoMapper.Map<IList<Item>>(list);
    }
}

0
投票

使用内部映射器时的几个注意点(即

context.Mapper

首先,尽量不要使用

context.Mapper.Map<TDestination>(...)
,改用
context.Mapper.Map<TSource, TDestination>(...)
,效果会好很多。

其次,在内部映射器中使用上下文会破坏封装。如果您需要设置内部对象中的值,请考虑以下两种解决方案:

如果您想在内部地图之后设置值

context.Mapper.Map<Source, Dest> (source, opts => opts.AfterMap((s, d) => 
    d.Something = source.Something))

如果您想在内部地图之前设置值

context.Mapper.Map<Source, Dest> (source, new Dest()
    {
        Something = source.Something
    })
© www.soinside.com 2019 - 2024. All rights reserved.