Jevgenij Nekrasov
Jevgenij Nekrasov

Reputation: 2760

Autofac + Automapper + custom ValueResolver

Let's say I have custom ValueResolver

public class AssessmentAttendiesResolver : ValueResolver<List<int>, ICollection<Expert>>
{
    private readonly IRepository<Expert> _expertRepository; 

    public AssessmentAttendiesResolver(IRepository<Expert> expertRepository)
    {
        _expertRepository = expertRepository;
    }

    protected override ICollection<Expert> ResolveCore(List<int> source)
    {
        return (ICollection<Expert>)_expertRepository.Query();
    }
}

In my Global.asax I registered my custom resolver and override Mapper.Initialize method like this.

builder.RegisterAssemblyTypes(currentAssembly).AsClosedTypesOf(typeof(ValueResolver<,>)).AsSelf();

    var container = builder.Build();
    Mapper.Initialize(conf => conf.ConstructServicesUsing(container.Resolve));

And CreateMap method

    Mapper.CreateMap<AssessmentCreateRequestModel, Assessment>()
        .ForMember(dest => dest.Attendies, opt => opt.ResolveUsing<AssessmentAttendiesResolver>().FromMember(item => item.Attendies));

When I run the code I get such exception

No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.

What should I change in order to successfully inject my repositories in my custom value resolver?

Upvotes: 3

Views: 1636

Answers (1)

Jim Bolla
Jim Bolla

Reputation: 8295

You are passing container.Resolve to your Mapper.Initialize call, which means all of your services will be resolved scoped to the container's lifetime scope. But the error message indicates that it's trying to resolve some service that is registered InstancePerHttpRequest.

You need to either change the relevant registrations so that they aren't scoped to the http request, or change the lamba you're passing to Mapper.Initialize to that it resolves from the current lifetime scope.

I don't know how when Automapper resolves services and how long it holds onto them to be able to tell you which solution is better. Ideally... IF Automapper only resolves services at the moment it needs them, and then immediately forgets about them, then I would recommend using my second solution, otherwise you'll be forced to use the first solution.

Upvotes: 2

Related Questions