Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.net core 2.0 AutoMapper IValueResolver dependency injection

I have tried most of the examples in the Google Results, Stackoverflow and in AutoMapper. But was not able to get the IValueResolverdependancy injection to work.

I have below service

public class StorageService : IStorageService
{
    private readonly BlobServiceSettings _blobServiceSettings;

    public StorageService(IOptions<BlobServiceSettings> blobServiceSettings)
    {
        _blobServiceSettings = blobServiceSettings.Value;
    }

    // some methods I need
}

This is my profile

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Building, BuildingEnvelope>(MemberList.None)
        .ForMember(dest => dest.ImageUrl, opt => opt.ResolveUsing<BuildingImageUrlResolver>());
    }
}

this is my IValueResolver

public class BuildingImageUrlResolver : IValueResolver<Building,         BuildingEnvelope, string>
{
    private readonly IStorageService _storageService;
    public BuildingImageUrlResolver(IStorageService storageService)
    {
        _storageService = storageService;
    }

    public string Resolve(Building entity, BuildingEnvelope envelope, string member, ResolutionContext context)
    {               
        return _storageService.MyMethod(entity.ImageFileName);
    }
}

I get the below error in my inner exception

No parameterless constructor defined for this object.

Not sure what I am doing wrong.

Thanks in advance Neo

like image 477
NeroIsNoHero Avatar asked Mar 22 '18 23:03

NeroIsNoHero


1 Answers

Lucian's suggestion is correct -- the AutoMapper.Extensions.Microsoft.DependencyInjection package is the way to go. Even if you don't want to use it, you'll have to do something similar.

I've had this very same problem and by using the extensions, you just modify the entrypoint from which you register AutoMapper and its configuration.

What the extensions do (source) is:

  1. Initializes Automapper with the configuration provided
  2. It scans for all classes you have that you could be implementing with dependency injection and registers them as transient, looking for implementations of the following:

    • IValueResolver
    • IMemberValueResolver
    • ITypeConverter
    • IMappingAction

    The assemblies that it will scan actually depend on the parameters that you provide on the call.

  3. If any of these can be actually instantiated, then they will be registered as transient implementation.
  4. And just like that, AutoMapper will request instances of these to the service provider, which will resolve them, and to do that, it will also resolve any pending dependencies.

Note that this is actually very simple -- the most difficult part is scanning the right assemblies and registering the right classes. You can do it manually too, but these extensions already take care of it for you.

Mind you, even when reflection has been improved a lot, this process is relatively slow, so try not to abuse it too much (for instance, in tests).


Finally, if none of that works for you, remember that you need to setup AutoMapper to use the dependency injection resolver too:

automapperConfiguration.ConstructServicesUsing(serviceProvider.GetService);
like image 194
Alpha Avatar answered Nov 17 '22 00:11

Alpha