Automapper: Support async operation in ValueResolver natively

Created on 9 Apr 2016  ·  17Comments  ·  Source: AutoMapper/AutoMapper

Currently I have the following code:

public class OrderNumberResolver : ValueResolver<Order, int>
{
    private readonly IOrderService _service;

    public OrderNumberResolver(IOrderService service)
    {
        _service = service;
    }

    protected override int ResolveCore(Order order)
    {
        return Task.Run(async () => await _service.GetOrder(order.OrderId))
                    .Result
                    .OrderNumber;
    }
}

But it would be nice to have something like that:

public class OrderNumberResolver : ValueResolver<Order, int>
{
    private readonly IOrderService _service;

    public OrderNumberResolver(IOrderService service)
    {
        _service = service;
    }

    protected override async Task<int> ResolveCoreAsync(Order order)
    {
        var order = await _service.GetOrder(order.OrderId);
        return order.OrderNumber;
    }
}

Most helpful comment

This is what I came up with: https://github.com/Narochno/Narochno.AsyncMapper

People seem to disagree that I should need to do this at all. Composing a domain object from multiple sources feels like a valid use case and some of those sources would need to be async.

All 17 comments

This will likely never happen. It would require the entire API be async,
just for a value resolver.

On Friday, April 8, 2016, Alexander Batishchev [email protected]
wrote:

Currently I have the following code:

public class OrderNumberResolver : ValueResolver
{
private readonly IOrderService _service;

public OrderNumberResolver(IOrderService service)
{
    _service = service;
}

protected override int ResolveCore(Order order)
{
    return Task.Run(async () => await _service.GetOrder(order.OrderId))
                .Result
                .OrderNumber;
}

}

But it would be nice to have something like that:

public class OrderNumberResolver : ValueResolver
{
private readonly IOrderService _service;

public OrderNumberResolver(IOrderService service)
{
    _service = service;
}

protected override async Task<int> ResolveCoreAsync(Order order)
{
    var order = await _service.GetOrder(order.OrderId);
    return order.OrderNumber;
}

}


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1226

Bummer.

Yeah I know. Plus I'd have to mix async and sync because there's no
guarantee I have just one or the other. It would just get ugly.

On Sunday, April 10, 2016, Alexander Batishchev [email protected]
wrote:

Bummer.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1226#issuecomment-208085576

Can you please evaluate this snippet? https://gist.github.com/JakeGinnivan/f345d34b7b8e9f04dc6d

Can you use that?

On Saturday, May 14, 2016, Alexander Batishchev [email protected]
wrote:

Bump.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1226#issuecomment-219201699

I'm not really familiar with the internal (context, etc.) so wondering is the right way to do async.

Well that makes two of us!

On Sat, May 14, 2016 at 11:36 AM, Alexander Batishchev <
[email protected]> wrote:

I'm not really familiar with the internal (context, etc.) so wondering is
the right way to do async.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1226#issuecomment-219229927

Can give a specific example !

Of async? I can't help you there.

On Saturday, May 14, 2016, djl [email protected] wrote:

Can give a specific example !


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1226#issuecomment-219262648

That snippet won't work as it's based off of an older version. I don't know enough about the AutoMapper context I think but I can't get it to work.

I also need to get async values from other sources to map to my destination. Using Value or Type converters results in the same problem. Doing .Result seems to cause deadlocks. Ugh.

The only way I could support this is to have the entire Map call be async.
I can't see that happening.

On Wed, Feb 8, 2017 at 11:15 AM, Adam Hathcock notifications@github.com
wrote:

That snippet won't work as it's based off of an older version. I don't
know enough about the AutoMapper context I think but I can't get it to work.

I also need to get async values from other sources to map to my
destination. Using Value or Type converters results in the same problem.
Doing .Result seems to cause deadlocks. Ugh.


You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1226#issuecomment-278394985,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGYMvEaSZYIZbI7k-trAUlZsXjDQWfpks5rafhFgaJpZM4IDgnG
.

The new version has a slight difference, you need to implement IValueResolver<in TSource, in TDestination, TDestMember> now, see Custom value resolvers.

It's not that simple.

The async resolver used stuff that isn't there anymore in the resolution context.

I think I've decided to wrap automapper and use it as a fallback outside of my async mapping. I'll post something when I have it.

This is what I came up with: https://github.com/Narochno/Narochno.AsyncMapper

People seem to disagree that I should need to do this at all. Composing a domain object from multiple sources feels like a valid use case and some of those sources would need to be async.

I am using ASP.NET Core where i would like to resolve for User GUID but since it's now async i cant resolve

    var user = await this.userManager.FindByIdAsync(ClaimTypes.NameIdentifier);

I can't resolve for the user, we need this!

I ended up using an await in the controller after calling _mapper.Map(), like this:

public async Task<IActionResult> Get(string id)
{
    var item = await _itemService.GetAsync(id);
    var model = _mapper.Map(item);
    model.UserName = (await _userService.GetAsync(item.UserId)).Name;
    ...
}

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings