I want to inject a AutoMapper.IMapper single instance as a singleton using NInject.
Actually, I'm un/mapping from/to objects using the AutoMapper static API. It's turned out obsolete and I'm looking forward to taking advantage of the ocassion to inject it using NInject.
Currently, I'm using this code in order to create my IMapper instance:
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.DigitalResourceProfile());
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.DigitalInputProfile());
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.FollowUpActivityProfile());
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.ResourceProfile());
As you can see, I've some profiles to initialize as well.
How should I build all that?
Until now, I've only been able to create a Module but I don't know how to make the bindings up.
public class AutoMapperModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind<AutoMapper.MapperConfiguration>().ToProvider<AutoMapperconfigurationProvider>().InSingletonScope();
this.Bind<AutoMapper.IMapper>().To<AutoMapper.Mapper>();
}
private class AutoMapperconfigurationProvider : IProvider<AutoMapper.MapperConfiguration>
{
public object Create(IContext context)
{
AutoMapper.MapperConfiguration instance = new AutoMapper.MapperConfiguration(
cfg =>
{
cfg.AddProfile(new UI.Mappings.Profiles.DigitalResourceProfile());
cfg.AddProfile(new UI.Mappings.Profiles.DigitalInputProfile());
cfg.AddProfile(new UI.Mappings.Profiles.FollowUpActivityProfile());
cfg.AddProfile(new UI.Mappings.Profiles.ResourceProfile());
}
);
return instance;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
}
I'd like to write this sentence each time I need a IMapper to map objects:
IMapper mapper = kernel.Get<IMapper>();
Any ideas?
I investigated this.
And I found the following:
In documentation we can found that we can do something like:
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<SomeProfile>();
cfg.CreateMap<Source, Dest>();
});
var mapper = config.CreateMapper(); // option 1
// or
var mapper = new Mapper(config); // option 2
Your code would work with using the option 2, because you have binding for configuration and for mapper.
But here we have two problems.
1) You need to change your first binding to bind MapperConfiguration as an interface IConfigurationProvider because the constructor of Mapper needs it:
public Mapper(IConfigurationProvider configurationProvider)
: this(configurationProvider, configurationProvider.ServiceCtor)
{
}
But here we got the second problem.
2) In automapper version 4.2.1 (as I believe you downloaded from NuGet) the Mapper class has only internal constructors. It has a public constructors in documentation (which is weird) and I think will have in a future release.
Therefore, for now you need to modify Load method to use option 1:
public override void Load()
{
this.Bind<AutoMapper.MapperConfiguration>().ToProvider<AutoMapperconfigurationProvider>().InSingletonScope();
this.Bind<AutoMapper.IMapper>().ToMethod(context => context.Kernel.Get<MapperConfiguration>().CreateMapper());
}
And then you can call IMapper mapper = kernel.Get<IMapper>(); to get the mapper instance.
It will use public IMapper CreateMapper() => new Mapper(this); and will create the instance of IMapper. Note: you need to use MapperConfiguration (not IConfiguration provider) to call CreateMapper method, it has the same situation as with public/internal constructors of Mapper.
That should help.
Related
I'm currently working out of a .NET 5 class library project with no Startup methods.
The idea behind what I'm, trying to achieve is that a developer can tap into this library and pass in an object. This object will run through the method, AutoMapper will grab the properties that align with the properties in the FirstDTO, then return a DTO that can be used throughout any other projects.
I'm relatively new to the AutoMapper bits and found this article here: How to configure Auto mapper in class library project?
I've liked this approach and have leveraged it to map a dynamic object to a DTO:
Configuration.cs
public static class Configuration
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg =>
{
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<MappingProfile>();
});
IMapper mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
Almost verbatim approach.
I have my MappingProfile.cs class:
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<dynamic, FirstDTO>();
CreateMap<dynamic, SecondDTO>();
}
}
When I call my base class I have the following method:
public class BaseLibraryClass : IBaseLibraryClass
{
public FirstDTO GetFirstObject(dynamic objectSentIn)
{
return Configuration.Mapper.Map<FirstDTO>(objectSentIn);
}
}
Which, in my though, should work.
Now when I write my xUnit unit tests, I'm having a failed Assert.Equal when comparing the FirstDTO with a built DTO:
private readonly IBaseLibraryClass baseLibraryClass = new BaseLibraryClass();
private readonly FirstDTOBuilder firstDTOBuilder = new FirstDTOBuilder();
[Fact]
public void TestSeparateObject()
{
// Arrange
FirstDTO firstDTO = firstDTOBuilder.DefaultDTO().Build();
// Act
FirstDTO result = baseLibraryClass.GetFirstObject(firstDTO);
// Assert
Assert.Equal(firstDTO, result);
}
What ends up happening when I debug this unit test, is that a DTO is built with the assigned properties via the Builder. It passes the DTO into GetFirstObject successfully with the populated properties, but when it hits the return, it returns a FirstDTO object type with properties that are all zeroed out, ultimately failing my unit test.
I feel like it's something glaringly obvious, but I cannot for the life of me figure out what's causing the properties to not map properly.
Any assistance would be greatly appreciated!
Automapper supports mapping from dynamic out of the box, no need to configure anything, so in your case removing profile from the configuration (or removing CreateMap's from the profile) should just work:
public static class Configuration
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg =>
{
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
});
IMapper mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
I am a bit new to unit testing with xUnit, and I have some problems with AutoMapper. I am getting the Mapper already initialized issue.
I am using Automapper 8.0.0., ASP.NET Core 2.2 and xUnit 2.4.1.
I am writing unit tests for my controllers.
I have unit tests in 3 different classes. Each class looks basically like this:
/* Constructor */
public ControllerGetTests()
{
/// Initialize AutoMapper
AutoMapper.Mapper.Reset();
MapperConfig.RegisterMaps();
/* Some mocking code here using Moq */
_controller = new MyController();
}
[Fact]
public async void Get_WhenCalled_ReturnsOkResult()
{
// Act
var okResult = await _controller.Get();
// Assert
Assert.IsType<OkObjectResult>(okResult);
}
/* etc. */
All three classes are similar and are basic tests for controllers.
All controllers are using AutoMapper.
I am using the same static class MapperConfig to register my mappings:
public static class MapperConfig
{
public static void RegisterMaps()
{
AutoMapper.Mapper.Initialize(config =>
{
config.CreateMap<SomeClass, SomeClassViewModel>();
config.CreateMap<SomeClassViewModel, SomeClass>();
});
}
}
I call this method in the constructor of each of the 3 test classes.
Before calling it, I call the Mapper.Reset() - some answers here suggest that:
Automapper - Mapper already initialized error
In the Test Explorer in VS when I select one test class and choose "Run selected tests", they all pass. However, when I select the main "Run all", some tests fail with the message Mapper already initialized. And each time it is different tests in different classes that fail.
I assume that different threads are created for different methods, but they are all trying to initialize the same mapper instance which throws an error.
However, I am not sure where am I supposed to call the initialization in one (and only one) place and have that same initialization be used for all my test classes (like I do in Startup.cs Configure method).
Thanks in advance.
Thanks to #Nkosi and #Dmitry Pavlov for their ideas.
What I ended up doing was:
1) Moving to instance API of the AutoMapper
This meant that the AutoMapper is now defined in Startup.cs in ConfigureServices method as:
public void ConfigureServices(IServiceCollection services)
{
// Auto Mapper Configurations
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MyMappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
//...
}
And injected into controllers like:
public class ItemsInstanceController : ControllerBase
{
private readonly IItemService _itemService;
private readonly IMapper _mapper;
public ItemsInstanceController(IItemService itemService, IMapper mapper)
{
_itemService = itemService;
_mapper = mapper;
}
//...
}
2) However, without spinning up a special test server, startup.cs methods are not run when tests are executed. So, for testing purposes, I ended up writing a small helper class implementing a singleton pattern on AutoMapper:
public class AutomapperSingleton
{
private static IMapper _mapper;
public static IMapper Mapper
{
get
{
if (_mapper == null)
{
// Auto Mapper Configurations
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MyMappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
_mapper = mapper;
}
return _mapper;
}
}
}
3) Now in my tests I just needed to create the controller like this:
controller = new ItemsInstanceController(itemServiceMock.Object, AutomapperSingleton.Mapper);
and the initialization was never run twice, only once on constructing the instance of the AutoMapper.
I have written a blog post where I go into much more details and explanations, so if you need more information, please go and read it.
Lazy loading of a wrapper class which initializes AutoMapper in it's constructor also works in the following manner:
public class StaticDependencies
{
public static Lazy<StaticDependencies> Initializer = new Lazy<StaticDependencies>();
public StaticDependencies()
{
MapperConfig.RegisterMaps();
}
public void AssertSetup()
{
// No Op
}
}
Then, in the constructor of your XUnit Test, simply refer to the static lazy loaded object:
public ControllerGetTests()
{
/// Initialize AutoMapper
StaticDependencies.Initializer.Value.AssertSetup();
/* Some mocking code here using Moq */
_controller = new MyController();
}
I am using asp.net core 2.0. I have DataAccess project and 20 API service project in my solution. And this number increasing every day. I will use AutoMapper. But I don't want to add automapper from NuGet for all projects. So, I want to add to the only DataAccess solution and adding profiles to DataAccess solution. And I want to call from API project by writing "mapper.Map(originalObject)". We can add Automapper to API project by adding startup.cs. But my DataAccess project is a class library. So it hasn't got startup.cs. How can I do this and can I access automapper from service projects? (I don't want to add automapper from NuGet to API)
There may be many solutions to this problem, I suggest only two of them and these aproaches may also change depending on your choice and scenario. Whether your helper class knows all the types that will be mapped or other user libraries need to register their own POCO classes, whether you prefer creating a mapper... You may also want to cache mappers and return it if it requested again.
Simple code samples are as follows
class Foo
{
public string Name { get; set; }
}
class Bar
{
public string Name { get; set; }
}
static void Main(string[] args)
{
//First approach usage
Bar _bar1 = MapperHelper.MapFrom<Bar>(new Foo() { Name = "bbbbb" });
//Second approach usage
IMyMapper _myMapper = MapperHelper.GetMapperFor<Foo, Bar>();
Bar _bar2 = _myMapper.MapFrom<Bar>(new Foo() { Name = "aaaAAA" });
//Third approach usage
Bar _bar3 = MapperHelper.Map<Bar, Foo>(new Foo() { Name = "cccc" });
}
public interface IMyMapper
{
T MapFrom<T>(object entity);
}
class MyMapper : IMyMapper
{
IMapper mapper;
public MyMapper(IMapper mapper)
{
this.mapper = mapper;
}
public T MapFrom<T>(object entity)
{
return mapper.Map<T>(entity);
}
}
public static class MapperHelper
{
static IMapper staticMapper;
static MapperHelper()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo, Bar>();
});
staticMapper = config.CreateMapper();
}
//First approach, create a mapper and use it from a static method
public static T MapFrom<T>(object entity)
{
return staticMapper.Map<T>(entity);
}
//Second approach (if users need to use their own types which are not known by this project)
//Create you own mapper interface ans return it
public static IMyMapper GetMapperFor<TSource, TDestination>()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<TSource, TDestination>();
});
var _mapper = config.CreateMapper();
return new MyMapper(_mapper);
}
//Third sample, create and use mapper inside a static helper method
//This is for mapping foreign types that this project does not
//include (e.g POCO or model types in other projects)
public static TDestination Map<TDestination, TSource>(TSource entity)
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<TSource, TDestination>();
});
var _mapper = config.CreateMapper();
return _mapper.Map<TDestination>(entity);
}
}
First one creates the configuration for known types and uses this mapper.
Second one creates a mapper and returns it in a wrapper class.
Third one creates and uses a mapper for mapping operation and only returns the mapped object.
Most people do not like static classes and methods since they cause strict unwanted dependencies, they can not be replaced easily. So, creating factory or utility classes, registering them to a dependency injection container and in jecting them where needed is preferred.
I have the following configuration.
public class AutoMapperProfile: Profile
{
public AutoMapperProfile()
{
CreateMap<DTO, Model>();
CreateMap<InnerDTO, NavigationPropertyModel>();
}
}
In my code I have
Model.NavigationProperty = mapper.Map(DTO.InnerDTO, Model.NavigationProperty);
seems to work very well but
Model = mapper.Map(DTO, Model);
doesn't. (InnerDTO isn't mapped)
PS: mapper is an instance of the automapper.
I want to stick with the second approach since the DTO can have more properties than just the InnerDTO.
I tried using Mapper.AssertConfigurationIsValid(); but got an exception
System.InvalidOperationException: 'Mapper not initialized. Call
Initialize with appropriate configuration. If you are trying to use
mapper instances through a container or otherwise, make sure you do
not have any calls to the static Mapper.Map methods, and if you're
using ProjectTo or UseAsDataSource extension methods, make sure you
pass in the appropriate IConfigurationProvider instance.'
Try to configure sub-property for CreateMap<DTO, Model>();.
public AutoMapperProfile()
{
CreateMap<DTO, Model>()
.ForMember(dest => dest.NavigationPropertyModel, opt => opt.MapFrom(src => src.InnerDTO));
CreateMap<InnerDTO, NavigationPropertyModel>();
}
Possibly what you are missing is to add your AutoMapperProfile class in Startup.cs.
public void ConfigureServices(IServiceCollection services) {
// Automapper conf
var config = new MapperConfiguration(configure => {
// Add your profile class here
configure.AddProfile(new AutoMapperProfile());
});
// Creating instance of automapper for dependency injection
var mapper = config.CreateMapper();
services.AddSingleton(mapper);
// More complex code here...
}
Subsequently, by dependency injection, you use automapper. In my particular case, I do it in the following way:
[Route("api/Permiso")]
[ApiController]
public class PermisoController : ControllerBase {
private readonly IMapper _mapper;
private readonly IBusinessLogicHelper _blh;
public PermisoController(BusinessLogicHelper blh, IMapper mapper) {
_blh = blh;
_mapper = mapper;
}
[HttpGet]
public IActionResult Get() {
try {
// Get raw data from entities
var resultsRaw = _blh.GetDataRaw();
if (resultsRaw == null) {
return NotFound();
}
// Mapping data from entity to DTO
var resultsDTO = _mapper.Map<ReturnDataDTO>(resultsRaw);
return Ok(resultsDTO);
} catch (Exception ex) {
// Custom ObjectResult for InternalServerError
return new InternalServerErrorObjectResult(ex.Message);
}
}
}
What is the correct way to configure AutoMapper for global use.
I want to set it once and then used though out the app.
i have a strong feeling this is wrong.
in fact i know this is wrong as this calls an new instance.
I want a global config and then how do you call it.
Can not find a good example!
this is what ive got: but its not what im wanting
public static class AutoMapperConfig
{
public static IMapper GetMapper()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<R_Logo, LogoDto>();
//lots more maps...?
});
IMapper mapper = config.CreateMapper();
return mapper;
}
}
and then usage:
var imapper = AutoMapperConfig.GetMapper();
var dest = imapper.Map<R_Logo, LogoDto>(logo);
UPDATE based on: pinkfloydx33
Call this once and then the config is done.
public static class AutoMapperConfig
{
public static void RegisterMappings()
{
AutoMapper.Mapper.Initialize(cfg => {
cfg.CreateMap<R_Logo, LogoDto>();
/* etc */
});
}
}
Here is the steps to configure the automapper in asp.net core mvc.
1. Create the mapping profile class which extends from Profile
public class ClientMappingProfile : Profile
{
public ClientMappingProfile ()
{
CreateMap<R_Logo, LogoDto>().ReverseMap();
}
}
2. Create the AutoMapper Configuration Class and add your mapping profile class here.
public class AutoMapperConfiguration
{
public MapperConfiguration Configure()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ClientMappingProfile>();
});
return config;
}
}
3. How we can use it.
var config = new AutoMapperConfiguration().Configure();
var iMapper = config.CreateMapper();
var dest = iMapper.Map<R_Logo, LogoDto>(logo);
Set this in your StartupConfig or StartUp file.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
.....
MappingDTOModelToModel.Configure();
}
}
Configuration of Mappings,
public static class MappingDTOModelToModel
{
private static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<R_Logo, LogoDto>()
.ForMember(x => x.ID,
m => m.MapFrom(a => a.ID))
.ForMember(x => x.FirstName,
m => m.MapFrom(a => a.FirstName)).ReverseMap();
}
}
}
Calling it in a method,
public class MyService
{
public void MyMethod(var model)
{
var myModel = Mapper.Map<LogoDto, R_Logo>(model);
}
}
Hope this helps,
You can use the static mapper api as outlined here.
For example, somewhere in your application, probably during startup you would configure the static (global) mapper using something like:
AutoMapper.Mapper.Initialize(cfg => {
cfg.CreateMap<Type1, Type2>();
/* etc */
});
Then, any time you need to use your "globally" configured mapper, you access it via the static Mapper property (which is an IMapper):
Type1 objectOfType1 = new Type1();
var result = AutoMapper.Mapper.Map<Type2>(objectOfType1);
You then have one mapper that has been configured for all the types/configurations/profiles you provide for the duration of your application without needing to configure individual mapper instances.
In short, you configure it once (perhaps at application startup). The static mapper instance (the IMapper) is then available anywhere throughout your application by accessing it via AutoMapper.Mapper.
Access via this static property is what you refer to as "globally" in your comments. Anywhere you need it just use AutoMapper.Mapper.Map(...) So long as you've called Initialize once first.
Note that if you call Initialize more than once on the static instance, each subsequent call overwrites the existing configuration.
WARNING
In a previous release of AutoMapper, the static mapper was removed. It was later added back in and I don't know if they guarantee that it will remain in future versions. The recommendation is to use your own configured instances of a mapper. You can store it in a static property somewhere if you need it. Otherwise you can look into profiles, etc for easy ways to configure your mapper so that having your own instance isn't necessarily a "hassle".
Our solution to this problem was to first create a selection of attributes that can decorate a class as being "Mappable" (either To, From or Both). Then you can initialize the AutoMapper in a single location, usually post application initialization and use Reflection to dynamically create a map for each instance of the decorated classes.
Here's an example:
var types = _myTypeFinder.Find(type =>
type.IsDefined(typeof(AutoMapperAttribute)) ||
type.IsDefined(typeof(AutoMapperFromAttribute)) ||
type.IsDefined(typeof(AutoMapperToAttribute))
);
Mapper.Initialize(cfg =>
{
foreach (var type in types)
{
AutoMapperHelper.CreateMap(type, cfg);
}
});
I have find best solution for configuration auto mapper in .Net Core.
Multiple Profile.
Just use this:
services.AddSingleton(provider => new MapperConfiguration(cfg =>
{
cfg.AddProfile(new sampleProfileMapper());
}).CreateMapper());