【问题标题】:Using the instance version of CreateMap and Map with a WCF service?将 CreateMap 和 Map 的实例版本与 WCF 服务一起使用?
【发布时间】:2009-11-03 17:37:22
【问题描述】:

在使用自动映射器时遇到了一些实际问题。我想我已经找到了解决方案,但不确定如何实施。

基本上我使用带有 ResolveUsing 和 ConstructedBy 的自定义映射将参数传递给构造函数,我知道大多数人在 global.asax 中设置过一次就忘记了。

但问题是我的方法(在 wcf 上)将不同的参数传递给 ResolveUsing 的构造函数......

在我使用 Mapper.CreateMap 和 Mapper.Map 这两个静态方法之前,当不同的请求通过方法(多用户)进入 wcf 服务时,它们似乎相互冲突。

在阅读了一些内容后,我可以使用 CreateMap 和 Map 的实例版本,以便每个单独的请愿书都有自己的地图并可以传入自己的参数。

但我似乎无法找到如何做到这一点。谁能解释一下?我真的被困住了......

时不时我会收到重复的键错误,并且我在构造函数上输入了一个日志跟踪,看起来 1 个请愿书正在覆盖另一个请愿书 - 因此是 Mapper 的静态版本。

我希望我是对的,但我找不到其他任何东西......

已编辑 - 我所拥有的示例

基本上所有映射都可以正常工作,因为我在大多数情况下都使用 MapFrom。

然后我创建一个我的解析器实例,并传入一个 URL。我在传递它之前检查了 url 并且它是正确的。但是一旦它返回它就会返回错误的 URL。

我需要传递 URL 的原因是它有变量,所以我需要替换变量...基本上有 2 个 url,具体取决于办公室,我到处都有日志,我可以看到我传递的内容但是一旦我把它传进去——它不是我传入的那个,如果这是有道理的,这很奇怪!!

它是一个 WCF 服务,客户端调用了该方法两次,传入 2 个不同的办公室,因此有 2 个不同的 URL。但它们总是返回相同的 URL。就像一个会话正在覆盖另一个...

我希望这是有道理的。

  SalesPointResolver newSalesPointResolver = new SalesPointResolver(returnReservationUrl, reservationSite.ReservationUrl, startDate, endDate, officeCode);


        Mapper.CreateMap<Models.Custom.House, DTO.House>()
            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.TaxIncluded,
                       opt => opt.MapFrom(src => src.Segments.FirstOrDefault().TaxIncluded))
            .ForMember(dest => dest.TaxPercentage,
                       opt => opt.MapFrom(src => src.Segments.FirstOrDefault().TaxPercentage))

            .ForMember(dest => dest.SalesPoints,
                       opt =>
                       opt.ResolveUsing(newSalesPointResolver))
            ;

找出失败的地方 - 但不知道为什么

查看我的 cmets 内嵌代码。在构造函数中,urlTemplate 到达,我将它保存在一个私有变量中,然后在重写的 ResolveCore 中它是别的东西:-)

我已经在那里放置了一些 log4net 日志,所以我可以看到发生了什么。

[Log]
public class SalesPointResolver : ValueResolver<Models.Custom.House, IList<DTO.SalesPoint>>
{
    private readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    private string urlTemplate;

    public SalesPointResolver (bool returnReservationUrl, string urlTemplate, DateTime startDate, DateTime endDate, string officeCode)
    {
        this.urlTemplate = urlTemplate;

        log.Error("passed in " + urlTemplate); // THIS IS PERFECT
        log.Error("I am now " + this.urlTemplate); // THIS IS PERFECT
    }

    protected override IList<DTO.SalesPoint> ResolveCore(House source)
    {
        this.house = source;

        log.Error("in  resolveCore :" + this.urlTemplate); // THIS IS RETURNING THE WRONG VALUE

临时解决方案

我已经做了一个临时解决方案,但它真的很糟糕。我确信 automapper 可以做我正在尝试的事情,但我显然做错了什么。

基本上,我通过 LINQ 返回一组记录(这是我的来源),因此我在每条具有正确 URL 模板的记录上输入了一个新字段。然后,我没有(通过构造函数)传递 url 模板,而是将它作为集合(源)上每条记录的属性提供......它工作得很好。

当然,这确实是补丁,并不理想,但它让我跑起来。

我哪里错了?

【问题讨论】:

  • 在您的示例中,您是否在运行时才知道源代码,但您知道在编译时映射到什么目标?
  • 不,我知道来源......但我正在使用构造函数将变量传递给 ResolveUsing,因此需要每次都创建地图,并且不需要由任何其他会话等共享
  • 如果这是一个 WCF 服务,它在自己的应用程序域中运行,因此地图不会与任何其他进程共享。听起来 ResolveUsing 的参数各不相同,但 ResolveUsing 通常采用源类型。您将参数传递到源类型之外的自定义值解析器的构造函数的原因是什么?
  • 您好,感谢您回复我,例如,我传入的是 RentalDays(租赁天数),因为它不在源中,因为我需要在我的 ResolveUsing 中使用它。
  • 我正在做的另一种类型是将列表传递给解析器以将列表返回到 src?为什么?因为列表是字符串的集合,但字符串包含变量..所以我的 resolveusing 用真实值替换变量并重建列表以将其返回给源..

标签: c# wcf mapping automapper


【解决方案1】:

是的,有一种方法可以使用 AutoMapper 的实例版本。

而不是...

Mapper.CreateMap<Dto.Ticket, Entities.Ticket>()

你可以使用:

var configurationStore =
    new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
var mapper = new MappingEngine(configurationStore);
configurationStore.CreateMap<Dto.Ticket, Entities.Ticket>()

【讨论】:

  • 我不知道 AutoMapper 的旧版本,但在当前版本中,Configuration 类被命名为ConfigurationStore
  • AllMappers() 方法现在是一个名为Mappers 的属性。
【解决方案2】:

响应Luke Woodwardscomment 更新语法:

ConfigurationStore store 
   = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
store.AssertConfigurationIsValid();
MappingEngine engine = new MappingEngine(store);

//add mappings via Profiles or CreateMap
store.AddProfile<MyAutoMapperProfile>();
store.CreateMap<Dto.Ticket, Entities.Ticket>();

【讨论】:

    【解决方案3】:

    好吧,看来我的问题被放弃了,但玩了一段时间后,我终于找到了一个很好的解决方法..

    基本上我在 Resolve 中,并且我有另一个 MAP,其中一个属性称为另一个 ResolveUsing ...

    这似乎有问题。另一个奇怪的事情是,每次启动或回收应用程序池时它都会失败。因此它第一次失败,然后就可以了,直到回收发生(我正在使用 wcf 应用程序)。

    所以我用 foreach 替换了第二个 Mapping,并在我原来的 Resolve 中做了我的映射 ...

    我已经把答案放在这里,以防将来可以帮助其他人..

    我使用 Mapper 静态方法进行映射,这些不在 global.asax 中,因为我需要根据某些因素传递不同的东西..

    我一直想知道是否可以使用实例版本的 mappper 来做到这一点,虽然它存在......但从未发现......

    但无论如何,现在一切都在 100% 工作......

    【讨论】:

    【解决方案4】:

    您是否考虑过使用接收目标对象的 Map 调用?

    var bar = new Bar("自定义每次调用");

    Mapper.Map(foo, bar);

    【讨论】:

    • 谢谢吉米,不知道我是否明白。如果我更改地图,那么我将无法访问我确实需要的标准 src 对象,因为我通常只将它映射到需要我调用特殊 ResolveUsing 并传递参数的几个属性上,因为有很多这里的逻辑......所以在解析时我仍然使用我的标准 src 对象,但在返回之前应用额外的逻辑(在这种情况下是 stringg) - 我误解你了吗?
    • 如果您能详细说明,我将不胜感激。
    • 我想我误解了 - 你有一点 sn-p 来显示你是如何使用 CreateMap 和 Map 调用的吗?
    • 嗨,吉米,感谢您回复我.. 是的,当然可以.. 我现在要更新我的问题..
    • 好的问题已经更新了一个我正在做的例子,使用“RESOLVEUSING”......在我使用ConstructedBy之前,但现在我正在创建实例并将其传递给ResolveUsing - 我希望这是有道理的..
    【解决方案5】:

    如果你想在 Automapper 中使用 Mapper 的实例化版本,那么我认为你可以使用 MappingEngine 类。我相信静态 Mapper 类实例化并配置一个 MappingEngine 对象来完成所有细节映射工作。

    这是一个将 IoC 应用于 Automapper 的示例(需要实例化 MappingEngine)

    http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/05/11/automapper-and-ioc.aspx

    【讨论】:

      猜你喜欢
      • 2014-06-06
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      相关资源
      最近更新 更多