0

I have a class that fetches some data from a database and I then map the data using AutoMapper. However, for some reason, mapper never gets a value injected so I get a NullReferenceException when I try to use mapper.

public class SearchesEditReview
{
    [Inject]
    public IMapper mapper { get; set; }
        
     public async Task<ViewEvent> GetEditFromId(int id)
     {
        //unrelated code

        return new ViewEvent
                {
                    Data = timelineinfo.FirstOrDefault(),
                    Medias = media,
                    //The below line breaks, saying mapper is null
                    Subjects = mapper.Map<List<DBSubject>, List<ViewSubject>>(subjects)
                };  
     }
}

My relevent Startup.cs looks like:

 public void ConfigureServices(IServiceCollection services)
{
      // Auto Mapper Configurations
      var mapperConfig = new MapperConfiguration(mc =>
      {
           mc.AddProfile(new MappingProfile());
      });

      services.AddHttpContextAccessor();

      IMapper mapper = mapperConfig.CreateMapper();
      services.AddSingleton(mapper);
}
2
  • docs.automapper.org/en/latest/Dependency-injection.html#asp-net-core Commented Nov 6, 2020 at 6:47
  • Use constructor injection. The @inject directive and the Inject attribute can only be used with Razor Components Commented Nov 6, 2020 at 7:02

2 Answers 2

1

Lets focus on the construction of SearchesEditReview, which seems to be unable to correctly bind the automapper property, while it's should be registered correctly.

You are using a binding with an [Inject] attribute, but that's not always clear how it works (well at least to me; there are ton's of frameworks, all doing it a little differently). For this reason I tend to use the constructor injection pattern:

public class SearchesEditReview
{
     public SearchesEditReview(IMapper mapper) //dependencies here
     {
        //attach to properties
     }
}

Next to the downside of don't having a parameter-less constructor, it has 2 advantages:

  1. you are forced to pass the parameter, so there will be no ambiguity, it is easier to debug
  2. You're independent of the DI framework. Which you'll seldom use.

As mentioned, for .net Core you can use a NuGet package for the .net Core Dependency Injection Framework:

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjections:

And register like this:

public void ConfigureServices(IServiceCollection services)
{
    //...
    //You'll need to pass in the assemblies containing your profiles,
    //or the profiles itself
    services.AddAutoMapper(typeof(YourProfile1),typeof(YourProfile2)); //etc
}

Note: The sometimes used loaded assembly scan GetAssemblies can be error prone. Since this occurs at startup, profile containing assemblies might not be loaded yet.

See this blog post or this documentation for more details.


Also keep in mind that you need to make sure the framework is able to construct SearchesEditReview.

Sign up to request clarification or add additional context in comments.

5 Comments

No, the mapper is ServiceLifetime.Transient in AM.DI for a while now.
And the GetAssemblies stuff is clearly error prone, so most of the times it's easier to simply pass the assemblies that define profiles.
Good point, I addessed that in the comment, but corrected it
Thanks for the answer, what is the accepted way to create an instance of that class now that it has a constructor?
Well, there are several of options: 1) create is manually, using new (not really reccommended), 2) create it in your controller, this will work by default: just add the SearchesEditReview to the controllers constructor 3) resolve it from the services provider. This should give you some hints, or search for Razor and dependency injection, also see: stackoverflow.com/questions/50788272/…
0

You cannot Inject into a class like that. The syntax your using would work fine on a .razor page however. Please see docs

Change your class. Note the constructor.

public class SearchesEditReview
{
    public SearchesEditReview(IMapper mapper)
    {
        this.mapper = mapper;
    }
       
    IMapper mapper { get; set; }

    public async Task<ViewEvent> GetEditFromId(int id)
    {
        //unrelated code

        return new ViewEvent
        {
            Data = timelineinfo.FirstOrDefault(),
            Medias = media,
            //The below line breaks, saying mapper is null
            Subjects = mapper.Map<List<DBSubject>, List<ViewSubject>>(subjects)
        };
    }
}

Startup.cs

...
services.AddSingleton(mapper);
services.AddSingleton<SearchesEditReview>();

4 Comments

How would I create an instance of SearchesEditReview with a constructor though?
@Bubinga Injection works in Controllers , Razor pages, Middleware etc. In a razor page you can use the [Inject] attribute. In a controller or middleware you simply put injectables in the constructor they will automatically be supplied.
@Bubinga For example in a .razor page if you [Inject] SearchesEditReview SearchesEditReview In a controller create a constructor if it doesn't already have one and add SearchesEditReview as a parameter. In my example the injection system will know how to construct it.
Ahhhh, that make sense. I just tried that and it works. Thank you :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.