'Call async method during automapper mapping
I'm trying to learn automapper (version 10.0.0) and I'm setting up my DTO input object to become my Entity Framework model object, so I did this:
CreateMap<RequestInputDTO, Request>()
.ForMember(x => x.RequestedById, x => x.Ignore())
.ForMember(x => x.RequestedForId, x => x.Ignore())
.ForMember(x => x.OrgHierarchyId, x => x.Ignore())
.AfterMap((src, dst) => {
dst.Uuid = Guid.NewGuid();
dst.RequestedUtc = DateTime.UtcNow;
});
And so far that part is working fine. However, for those three properties I told it to ignore, I have to do database lookups. They send me a name for example, I grab the ID of the corresponding record and then use that for the ID. So when I receive the request I'm doing this:
var request = _mapper.Map<Request>(dto);
request.RequestedById = await WwidToIdAsync(dto.RequestedByWwid);
request.OrgHierarchyId = await OrgHierarchyNumberToIdAsync(dto.RequestedForOrgHierarchyCode);
request.RequestedForId = await WwidToIdAsync(dto.RequestedForWwid);
While that seems to be doing the right thing, I don't like that I've now disconnected those three items from the automapping. It'd be too easy for someone to forget to do it. I can't figure out how to get the three lines handled automatically during the mapping since AfterMap isn't async.
Solution 1:[1]
Had the same issue with .NET 6.0. I don't know if you had the issue on Core or prior versions, but here's a solution (or maybe workaround) for AutoMapper 11 and .NET 6.0 (can be applied to any Core version, because it is using dependency injection).
- I've added a new service where mentioned async methods are located:
// Input and output parameter types were defined based on guessing from names :)
public interface IMyService
{
Task<bool> WwidToIdAsync(bool requestedByWwid);
Task<int> OrgHierarchyNumberToIdAsync(bool requestedForOrgHierarchyCode);
}
public class MyService : IMyService
{
public async Task<bool> WwidToIdAsync(bool requestedByWwid)
{
// Your db lookup here
}
public async Task<int> OrgHierarchyNumberToIdAsync(bool
requestedForOrgHierarchyCode)
{
// Another db lookup here
}
}
- Register the service above in dependency container:
services.AddScoped<IMyService, MyService>();
- Here's where all the magic happens: creating new MappingAction and injecting IMyService to it.
public class RequestInputMappingAction : IMappingAction<RequestInputDTO, Request>
{
private readonly IMyService _myService;
public RequestInputMappingAction(IMyService myService)
{
_myService = myService;
}
public void Process(RequestInputDTO source, Request destination, ResolutionContext context)
{
destination.Uuid = Guid.NewGuid();
destination.RequestedUtc = DateTime.UtcNow;
destination.RequestedById = _myService.WwidToIdAsync(source.RequestedByWwid).GetAwaiter().GetResult();
destination.OrgHierarchyId = _myService.OrgHierarchyNumberToIdAsync(source.RequestedForOrgHierarchyCode).GetAwaiter().GetResult();
destination.RequestedForId = _myService.WwidToIdAsync(source.RequestedForWwid).GetAwaiter().GetResult();
}
}
- And the final step -
CreateMap
CreateMap<RequestInputDTO, Request>()
.AfterMap<RequestInputMappingAction>();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
