3

I'm on AutoMapper 4.2 and I cant figure out why I'm getting this error

Autofac.Core.Registration.ComponentNotRegisteredException The requested service 'Navigator.ItemManagement.Data.MappingProfiles.ReportPreferenceReportUserIdsResolver' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

I'm getting this error for my one of my value resolvers

public class ReportPreferenceProfile : Profile
    {
        protected override void Configure()
        {
            CreateMap<ReportPreference, ReportPreferenceSummaryDto>()
                .ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
                .ForMember(d => d.Name, o => o.MapFrom(s => s.Name))
                .ForMember(d => d.ReportUserIds, o => o.ResolveUsing<ReportPreferenceReportUserIdsResolver>());
        }
    }

public class ReportPreferenceReportUserIdsResolver : ValueResolver<IList<ReportUser>, IList<Guid>>
    {
        protected override IList<Guid> ResolveCore(IList<ReportUser> source)
        {
            return source.Select(r => r.UserId).ToList();
        }
    }

I've registered this in my Autofac module

protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<ReportPreferenceReportUserIdsResolver>().As<IValueResolver>();

            //register all profile classes in the calling assembly
            var profiles =
                from t in typeof(Navigator.ItemManagement.Data.MappingProfiles.PlaceMapperProfile).Assembly.GetTypes()
                where typeof(Profile).IsAssignableFrom(t)
                select (Profile)Activator.CreateInstance(t);

            builder.Register(context => new MapperConfiguration(cfg =>
            {
                foreach (var profile in profiles)
                {
                    cfg.AddProfile(profile);
                }


            })).AsSelf().SingleInstance();

            builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
                .As<IMapper>()
                .SingleInstance();
        }

UPDATE 1

I tried the suggestion from Lucian Bargaoanu and replaced

builder.RegisterType<ReportPreferenceReportUserIdsResolver>().As<IValueResolver>();

with

builder.RegisterType<ReportPreferenceReportUserIdsResolver>().AsSelf();

Now the error I get is

System.ObjectDisposedException

This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored. Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.

Mapping types: ReportPreference -> IList1 Navigator.ItemManagement.Core.ItemAggregate.ReportPreference -> System.Collections.Generic.IList1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

Destination path: ReportJobSummaryDto.Reports.Reports.Reports0[0].ReportUserIds0[0]

Source value: Navigator.ItemManagement.Core.ItemAggregate.ReportPreference ---> AutoMapper.AutoMapperMappingException:

Mapping types: ReportPreference -> IList1 Navigator.ItemManagement.Core.ItemAggregate.ReportPreference -> System.Collections.Generic.IList1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

Destination path: ReportJobSummaryDto.Reports.Reports.Reports0[0].ReportUserIds0[0]

Raihan Iqbal
  • 407
  • 3
  • 16
  • Check [the docs](https://github.com/AutoMapper/AutoMapper/wiki/Dependency-injection). – Lucian Bargaoanu Aug 04 '17 at 04:11
  • @LucianBargaoanu The docs are for the latest version which is 5+. In version 4 you have to implement ValueResolver but in the latest version you implement IValueResolver. Also the doc is related to injecting services into your value resolver but I dont need anything of that sort. My value resolver itself is not being picked up by AutoFac. – Raihan Iqbal Aug 04 '17 at 04:47
  • The differences are irrelevant, just follow the same steps and you'll be ok. – Lucian Bargaoanu Aug 04 '17 at 05:06
  • 1
    Considering your ValueResolver has no deps you could use just use `o.ResolveUsing(new ReportPreferenceReportUserIdsResolver());` in your mapping profile as a workaround. – Peter Riesz Aug 31 '17 at 13:37

2 Answers2

2

I arrived at this Q&A after encountering the same problem.

As @PeterRiesz mentioned in comments, since your IValueResolver does not require any dependencies, the simplest solution here would be to change the form in which you wire up the value resolver to just take a manual new instance:

o.ResolveUsing(new ReportPreferenceReportUserIdsResolver())

This wouldn't require any registration with the Autofac container.

However, you may wish to inject services in to it, or just want to register it with Autofac for other reasons and maintainability.

First, ensure that you've registered your IValueResolver type with Autofac as @LucianBargaoanu answered:

builder.RegisterType<ReportPreferenceReportUserIdsResolver>().AsSelf();

I was defining my AutoMapper registrations the same way as you, and as a result was also getting the same error you show above.

After much research and trial and error to resolve the error myself, I found this StackOverflow Q&A which led me in the right direction.

You are already setting up the service function for AutoMapper to use to resolve dependencies here:

builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
    .As<IMapper>()
    .SingleInstance();

However, as the error states, the context c has been disposed by the time this actually gets executed. The way to fix this is to rewrite the lambda registration as follows:

builder.Register(c =>
{
    //This resolves a new context that can be used later.
    var context = c.Resolve<IComponentContext>();
    var config = context.Resolve<MapperConfiguration>();
    return config.CreateMapper(context.Resolve);
})
.As<IMapper>()
.SingleInstance();

An additional means of registering the service resolver exists as well. You can do it in the MapperConfiguration registration instead as follows:

builder.Register(c =>
{
    //Again, we must store a new instance of a component context for later use.
    var context = c.Resolve<IComponentContext>();
    var profiles = c.Resolve<IEnumerable<Profile>>();

    return new MapperConfiguration(x =>
    {
        foreach (var profile in profiles)
        {
            x.AddProfile(profile);
        }

        //Registering the service resolver method here.
        x.ConstructServicesUsing(context.Resolve);
    });
})
.SingleInstance()
.AsSelf();

Either of these appears to be equivalent. I think the latter is cleaner personally.

The take away here is that a new context needs to be resolved in the top-level lambda since the instance being passed in will be disposed by the time the lambda is actually executed.

crush
  • 16,713
  • 9
  • 59
  • 100
-1

Try

builder.RegisterType<ReportPreferenceReportUserIdsResolver>().AsSelf();
Lucian Bargaoanu
  • 3,336
  • 3
  • 14
  • 19
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/16930976) – Lukas Körfer Aug 04 '17 at 07:21
  • I've seen this before. Did you? Why do you say that? – Lucian Bargaoanu Aug 04 '17 at 07:46
  • Your answer seems to be a guess that applies a minimal change, which may or may not solve the problem. Use comments for this. For answers, please explain why and how the provided code fixes his particular problem instead of posting one-line code-only posts. – Lukas Körfer Aug 04 '17 at 07:59
  • I think this is enough for someone to understand what's wrong or replace my answer with a more detailed version, so please do that if you can, but don't say it doesn't answer the question unless you can say why exactly is that. – Lucian Bargaoanu Aug 04 '17 at 08:03
  • My first comment was auto-generated by the review system, because in my opinion you should've used a comment instead of an answer for this one line of code without explanation. Unfortunately, the generic text did not match the problem in this case. – Lukas Körfer Aug 04 '17 at 08:15
  • I understand. But after the fact people usually just read the answers and ignore the comments. The best solution here would be for a better answer to replace mine. But when it's the only answer it should stand. – Lucian Bargaoanu Aug 04 '17 at 08:35
  • @LucianBargaoanu Sorry for the delayed response. I was off for a few days. I tried your suggestion and I get a different error. – Raihan Iqbal Aug 11 '17 at 02:27
  • That has nothing to do with AM. – Lucian Bargaoanu Aug 11 '17 at 04:18
  • I tried AsSelf() and also got System.ObjectDisposedException – Peter Riesz Aug 31 '17 at 13:33