Writing Custom Resolver with AutoMapper to Leverage Dependency Injection in .NET Core
AutoMapper is a fantastic tool in the .NET ecosystem that simplifies “mapping” the values of properties from one object of say “ClassOne” to the properties of another object which could be “ClassTwo.” For most use cases, the mapped value can be easily determined from the source object and usual maps to a field on the target object named differently or needs to be ignored.
The other day, I ran into an edge case where I needed to use a URL value from our application configuration in a particular mapping. It wasn’t obvious how to access the configuration I registered as a dependency in our application’s startup. Luckily, I stumbled on IValueResolver in AutoMapper, and I wanted to share my work so you can find yourself time if you run into this situation.
The Custom Resolver
As I stated above, I needed a value from the configuration I registered as an injectable dependency during program Startup. I needed to create a Custom Resolver to solve this issue that implements an AutoMapper interface called IValueResolver. This interface requires you to implement a method called Resolve, which provides access to the source and target object and will set the destination value to the function's output.
In the Resolver, we can declare a constructor, which allows us to inject the configuration object that we registered on startup. Without this resolver, we have no way to inject that configuration in a regular MappingProfile without introducing some very tight coupling to our top-level mapping class. Using this method, we only inject dependencies when they are needed in a particular mapping.
using AutoMapper;
using Microsoft.Extensions.Configuration
public class MyResolver : IValueResolver<SourceType, TargetType, string>
{
private readonly string_myAppUrl
public MyResolver(IConfigurationconfiguration)
{
_myAppUrl=configuration["MyAppUrl"];
}
public string Resolve(
SourceType source,
TargetType target,
string destMember,
ResolutionContext context)
{
return $"{_myAppUrl}/api/Orders/{source.OrderId}";
}
}
Using the Custom Resolver
We add the property mapping in the code below and tell AutoMapper to use the Custom Resolver when mapping the value.
using AutoMapper;
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<SouceType, TargetType>()
.ForMember(x=>x.Url, opt=>opt.MapFrom<MyResolver>());
}
}
Dependency Injection
If you set up AutoMapper with Dependency Injection using their extension method, this resolver should automatically work. We kept our mapping profiles in another project, so I had to add explicit registrations, which was kind of a pain to figure out but is a small add.
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// May not need this if mappings are in same project
services.AddTransient < MyResolver >();
}
Source: Medium - Doug Hill
The Tech Platform
Comments