Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ResolutionContext creation customization in Automapper

Tags:

c#

automapper

guys.

Maybe someone has the same problem.

I have some cached variables in the MemoryCache (standard non-distributed in-memory implementation of Microsoft.Extensions.Caching.Memory.IMemoryCache). So, I also have mappings I use for Response/DTO creation. Some of them use variables from MemoryCache. But now I must always pass it through

opts => 
{
   opts.Items.Add(variableName1, variableValue1);
   opts.Items.Add(variableName2, variableValue2);
   ... 
}

or I need to pass each time MemoryCache the same way.

Is it possible to set up a global configuration of ResolutionContext which allows me to pass all variables from MemoryCache I need in the time of the ResolutionContext creation? Unfortunately, BeforeMap isn't a solution - It has no DI mechanism for IMemoryCache resolving. And as I know It can be only one in the mapping structure - Automapper skips all BeforeMap after the first one.

Thank you.

like image 313
Dmitriy Avatar asked Oct 19 '25 05:10

Dmitriy


1 Answers

Instead of using the ResolutionContext, you can implement a custom IMemberValueResolver, which can get the IMemoryCache dependency injected.
By doing so, there's no need to seed theResolutionContext with key/value pairs (being copied from the IMemoryCache).

The FromMemoryCacheResolver below resolves the value for the requested cache key from the injected IMemoryCache.

public class FromMemoryCacheResolver<TDestMember>
    : IMemberValueResolver<object, object, object, TDestMember>
{
    private readonly IMemoryCache _memoryCache;

    public FromMemoryCacheResolver(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }

    public TDestMember Resolve(
        object source, object destination, object cacheKey, TDestMember destMember,
        ResolutionContext context
        )
    {
        if (_memoryCache.TryGetValue(cacheKey, out object value)
            && (value != null)
            )
        {
            return (TDestMember)value;
        }

        return default(TDestMember);
    }
}

Example

public class Source
{
    public int Id { get; set; }
}

public class Target
{
    public decimal DecimalValue { get; set; }

    public string StringValue { get; set; } 
}

Given the above Source and Target classes, you can define an AutoMapper mapping that sets a target property to the value bound to a fixed cache key (see DecimalValue rule) or a dynamic cache key (including a property value of the source object, see StringValue rule).

CreateMap<Source, Target>()
    .ForMember(
        o => o.DecimalValue,
        opt => opt.MapFrom<FromMemoryCacheResolver<decimal>, object>(
            _ => "constant-cache-key"
    ))
    .ForMember(
        o => o.StringValue,
        opt => opt.MapFrom<FromMemoryCacheResolver<string>, object>(
            src => $"dynamic-cache-key-{src.Id}"
    ));
like image 108
pfx Avatar answered Oct 21 '25 20:10

pfx



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!