question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

InvalidOperationException when using DI in collection element mapping

See original GitHub issue

I’ve ran into this issue last week and spent quite some time looking into it, I would love to get some explanation about the implementation chosen and what the implications are for the workaround.

Background

Our existing DTOs use IEnumerable<T> to represent child collection properties. Some of the DTOs are complex and their child properties are of type of yet another DTO. We define custom conversions of each POCO to DTO. Certain POCO properties are mapped using a service injected with MapContext.

Issue

When the destination type is evaluated, the value is set to SelectListIterator and no instantiated until after the IoC container scope is disposed and therefore generating the following exception:

System.InvalidOperationException: Mapping must be called using ServiceAdapter
    at Mapster.TypeAdapterExtensions.GetService[TService](MapContext context) in D:\Dev\Repos\GitHub\Mapster\src\Mapster.DependencyInjection\TypeAdapterExtensions.cs:line 19
   at lambda_method(Closure , Poco )
   at System.Linq.Enumerable.SelectListIterator`2.MoveNext()
...

If we change the destination type properties to use List<T> or array, it works as intended. But we are talking about hundreds of occurrences that will need to be modified, so we should avoid that at all cost. Especially since AutoMapper works great with this scenario.

Steps to Reproduce

This is the simplified scenario written as test within Mapster.DependencyInjection.Tests.InjectionTest: (in the test, I’m mapping directly using .Map<IEnumerable<Dto>>(... so please don’t suggest to change it to List<Dto>)

        [TestMethod]
        public void InjectionInsideCollection()
        {
            var config = new TypeAdapterConfig();
            config.NewConfig<Poco, Dto>()
                .Map(dest => dest.Name, _ => MapContext.Current.GetService<IMockService>().GetName());

            IServiceCollection sc = new ServiceCollection();
            sc.AddScoped<IMockService, MockService>();
            sc.AddSingleton(config);
            sc.AddScoped<IMapper, ServiceMapper>();

            var sp = sc.BuildServiceProvider();

            IEnumerable<Dto> dtos;
            using (var scope = sp.CreateScope())
            {
                var mapper = scope.ServiceProvider.GetService<IMapper>();
                var pocos = new List<Poco> {new Poco {Id = "bar"}};
                dtos = mapper.Map<IEnumerable<Dto>>(pocos);
            }
            
            dtos.ShouldNotBeEmpty();
            dtos.Count().ShouldBe(1);
            dtos.Single().Name.ShouldBe("foo");
        }

Workaround

I categorize it as a workaround since I’m not sure what the implications are and if none, I think that should be the default behavior. We added the following default configuration:

config.Default.Settings.AvoidInlineMapping = true;

Any help, clarification, suggestion is appreciated…

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
chaowlertcommented, May 7, 2021

Too bad, it is because of IEnumerable<> behavior. Enumerable computed lazily outside service provider scope.

You have 2 choices.

  1. Using List<>
  2. Move dtos.Count(), dtos.Single() inside service provider scope.
0reactions
asymetrixscommented, Jan 26, 2023

This looks like it is similar to #230 I wrote a little solution/workaround on StackOverflow with an explanation on why it works this way: https://stackoverflow.com/questions/69749350/mapster-context-is-null-in-nested-mappings/75249680#75249680

Read more comments on GitHub >

github_iconTop Results From Across the Web

InvalidOperationException when using DI in collection ...
Issue. When the destination type is evaluated, the value is set to SelectListIterator and no instantiated until after the IoC container scope is ......
Read more >
Automapper IMapper issues with Dependency Resolver
This error occours because you haven't registered a mapper which should be resolved on the IMapper interface on the service collection.
Read more >
VS can't rename C# class with "InvalidOperationException"
Dear, this problem is caused by the problem of using collections or threads, not the vs itself. OK, good to know. 0 ...
Read more >
Dependency Injection Into Views In ASP.NET Core MVC
This method is used to map the abstract types to concrete services which are instantiated separately for every object that requires this service ......
Read more >
Using Simple Injector
An instance of Container is used to register mappings between each abstraction (service) and its corresponding implementation (component). Your application code ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found