AutoMapper - 传递参数给自定义解析器的奇怪行为

6
尽管我对AutoMapper相对陌生,但我在开发小型项目时使用了它。以前我从未遇到过问题,但是现在我在向自定义解析器传递参数时遇到了一些奇怪的行为。
以下是情景:我从仓库获取消息列表,然后将它们映射到前端友好的版本。没有花哨的东西,只是对象之间的正常映射。我有一个字段在前端对象中,用于告诉某个用户是否已经为该消息投票,这就是我使用自定义解析器的原因(它是第二个“ForMember”)。
    public List<SupportMessageUi> GetAllVisible(string userId)
    {
        Mapper.CreateMap<SupportMessage, SupportMessageUi>()
              .ForMember(dest => dest.Votes,
                         opt => opt.ResolveUsing<SupportMessageVotesResolver>())
              .ForMember(dest => dest.UserVoted,
                         opt => opt.ResolveUsing<SupportMessagesUserVotedResolver>()
                                   .ConstructedBy(() => new SupportMessagesUserVotedResolver(userId)));

        var messages = _unitOfWork.MessagesRepository.Get(m => m.Visible);

        var messagesUi = Mapper.Map<List<SupportMessageUi>>(messages);

        return messagesUi;
    }

我在调用一个网络服务的方法时遇到了问题:第一次调用网络服务(使用网络服务控制台),一切都运行得很完美。例如,如果我将"555"作为userId传递进入该方法,那么我会得到正确值:“输入图像描述这里” 在自定义解析器中,该值被传递到构造函数:“输入图像描述这里” 返回的结果是正确的。问题来了,第二次调用该服务时,通过传递不同的参数(这次是“666”),传递到Custom Resolver构造函数的参数是旧的(' 555 ')。下面是我的意思:
在映射对象之前,我们可以看到传递给构造函数的值是正确的(' 666'):“输入图像描述这里” 但是,在传递到Resolver的构造函数时,该值是错误的,而且是旧值(' 555 '):“输入图像描述这里” 所有后续对该服务的调用都会在Custom Resolver构造函数中使用原始值(' 555 '),而不管我传递给服务的值如何(如果我从另一个浏览器进行调用,也会发生这种情况)。如果我关闭服务器并重新启动它,则可以传递新参数(直到再次关闭为止,将在所有其他调用中使用该参数)。
你知道为什么会出现这种情况吗?
2个回答

8
这是因为AutoMapper.CreateMap是一个静态方法,只需要调用一次。在您的Web方法中使用CreateMap代码时,您试图每次调用Web服务上的该方法时都调用它。由于Web服务器进程在调用之间保持活动状态(除非您像您所说的那样重新启动它),因此静态映射保持不变。因此,如您在答案中所说,调用AutoMapper.Reset是必要的。

但建议您将映射创建放在AppStartGlobal或静态构造函数中,以便只调用一次。有一些调用Map的方式可让您传递值,因此您不需要尝试使用ValueResolver的构造函数来精细处理事情。

以下是使用ValueResolver的示例(请注意更改为实现IValueResolver而不是继承ValueResolver<TSource,TDestination>):

[Test]
public void ValueTranslator_ExtraMapParameters()
{
    const int multiplier = 2;
    ValueTranslator translator = new ValueTranslator();
    Mapper.AssertConfigurationIsValid();

    ValueSource source = new ValueSource { Value = 4 };
    ValueDest dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(8));

    source = new ValueSource { Value = 5 };
    dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(10));
}

private class ValueTranslator
{
    static ValueTranslator()
    {
        Mapper.CreateMap<ValueSource, ValueDest>()
            .ForMember(dest => dest.Value, opt => opt.ResolveUsing<ValueResolver>().FromMember(src => src.Value));
    }

    public ValueDest Translate(ValueSource source, int multiplier)
    {
        return Mapper.Map<ValueDest>(source, opt => opt.Items.Add("multiplier", multiplier));
    }

    private class ValueResolver : IValueResolver
    {
        public ResolutionResult Resolve(ResolutionResult source)
        {
            return source.New((int)source.Value * (int)source.Context.Options.Items["multiplier"]);
        }
    }
}

private class ValueSource { public int Value { get; set; } }
private class ValueDest { public int Value { get; set; } }

下面是使用 TypeConverter 的示例:

[Test]
public void TypeTranslator_ExtraMapParameters()
{
    const int multiplier = 3;
    TypeTranslator translator = new TypeTranslator();
    Mapper.AssertConfigurationIsValid();

    TypeSource source = new TypeSource { Value = 10 };
    TypeDest dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(30));

    source = new TypeSource { Value = 15 };
    dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(45));
}

private class TypeTranslator
{
    static TypeTranslator()
    {
        Mapper.CreateMap<TypeSource, TypeDest>()
            .ConvertUsing<TypeConverter>();
    }

    public TypeDest Translate(TypeSource source, int multiplier)
    {
        return Mapper.Map<TypeDest>(source, opt => opt.Items.Add("multiplier", multiplier));
    }

    private class TypeConverter : ITypeConverter<TypeSource, TypeDest>
    {
        public TypeDest Convert(ResolutionContext context)
        {
            TypeSource source = (TypeSource)context.SourceValue;
            int multiplier = (int)context.Options.Items["multiplier"];

            return new TypeDest { Value = source.Value * multiplier };
        }
    }
}

private class TypeSource { public int Value { get; set; } }
private class TypeDest { public int Value { get; set; } }

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接