8

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

Komal12
  • 3,340
  • 4
  • 16
  • 25
NeroIsNoHero
  • 293
  • 4
  • 13

1 Answers1

3

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);
Alpha
  • 7,586
  • 8
  • 59
  • 92
  • Apologies for the delay getting back, was on holidays and back now. I did try using the AutoMapper.Extensions.Microsoft.DependencyInjection earlier and was the same issue, I wonder if its something to do with the project. IStorageService also has a dependency injection like below public StorageService(IOptions blobServiceSettings) { _blobServiceSettings = blobServiceSettings.Value; } Wonder that is is an issue, might remove it and try, But I won't be able to remove it permanently as service is widely used across project. Thanks – NeroIsNoHero May 07 '18 at 02:45
  • I tried removing the DI in the IStorageService, but still erros. definatly with the resolver DI, any more ideas? – NeroIsNoHero May 07 '18 at 02:52
  • @NeroIsNoHero Did you try to pass parameters to the extension methods so that it scans the right assemblies? – Alpha May 07 '18 at 10:58
  • Hi Alpha Thank you for your replay, Yes I do this on startup.cs [code]services.AddAutoMapper(typeof(IStorageService));[/code] If I put a breakpoint in the constructor of "StorageService" it does hit and it does resolve its dependencies (getting the URL from app settings) Error mapping types. Mapping types: Building -> BuildingEnvelope Building -> BuildingEnvelope Type Map configuration: Building -> BuildingEnvelope Building -> BuildingEnvelope Property: ImageUrl Any Ideas, been straggling with this for a few months now, would be great to get it done. Thanks – NeroIsNoHero May 23 '18 at 02:06
  • as soon as I remove the DI from constructor, no errors – NeroIsNoHero May 23 '18 at 02:15
  • @NeroIsNoHero Based on that error it seems the resolver is getting called (yay!) and it's just failing internally. I'd say you debug it and verify why it's blowing up -- it's the easier approach, as Automapper won't tell you in detail what the exception was, just that the mapping failed. (Easy approach: try/catch the whole Resolve method and set a breakpoint in the catch.) – Alpha May 26 '18 at 23:35