There is no implicit conversion from MapperConfiguration to IMapperConfiguration - c#

I am using Automapper and StructureMap in my Web API application.
I am getting the following error message during compilation. I have installed the following:
StructureMap 4.5
StructureMap.MVC5 3.1.1.134
StructureMap.web 4.0.0.315
StructureMap.webapi2 3.0.4.125
There is no implicit conversion from MapperConfiguration to IMapperConfiguration
at the following line of code:
For<IMapperConfiguration>().Use(config);
The full code is below
public class DefaultRegistry : Registry
{
#region Constructors and Destructors
public DefaultRegistry()
{
var profiles = from t in typeof(DefaultRegistry).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile) Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
//Create a mapper that will be used by the DI container
var mapper = config.CreateMapper();
//Register the DI interfaces with their implementation
For<IMapperConfiguration>().Use(config);
For<IMapper>().Use(mapper);
//Register the UserRepository and pass instance of Mapper to its constructor
For<IMovieBusiness>().Use<MovieBusiness>().Ctor<IMapper>().Is(mapper);
For<IConnectionFactory>().Use<ConnectionFactory>();
For<IMovieRepository>().Use<MovieRepository>();
For<IUnitOfWork>().Use<UnitOfWork>();
For<IMovieService>().Use<MovieService>();
For<IMovieBusiness>().Use<MovieBusiness>();
}

MapperConfiguration implements IConfigurationProvider only in Automapper 6.1.0.

Related

How to use Automapper configuration in ASP.NET MVC controllers

I am using AutoMapper to convert my models into view models. I have the configuration all setup, tested, and working. For reference, this is what my configure method looks like:
public static MapperConfiguration Configure()
{
MapperConfiguration mapperConfiguration = new MapperConfiguration(cfg => {
cfg.CreateMap<Ebill, EbillHarvesterTaskVM>()
cfg.CreateMap<Note, NoteVM>();
cfg.CreateMap<LoginItem, LoginCredentialVM>()
cfg.CreateMap<Login, ProviderLoginVM>()
});
mapperConfiguration.CreateMapper();
return mapperConfiguration;
}
This is what my test looks like:
public void ValidConfigurationTest()
{
var config = AutoMapperConfig.Configure();
config.AssertConfigurationIsValid();
}
What I don't understand is how to access it to actually map one object to another from within my Controller. I know I can call this config method when my app starts up, I have an application configuration class that is called from global.asax that calls my automapper configuration method. I'm not sure how to access all of this from within the controller though. I've read things that say dependency injection, but I'm not familiar enough with what that means to know how to apply it.
I've used Automapper in the past, but I think I implemented the now unavailable static API. Where the config method looks like this:
public static void RegisterMappings()
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<ManagementCompany, ManagementCompanyViewModel>();
cfg.CreateMap<ManagementCompanyViewModel, ManagementCompany>();
});
}
The configuration is called in Global.asax
AutoMapperConfig.RegisterMappings();
And where you can call this within a controller to utilize mapping:
AutoMapper.Mapper.Map(managementCompany, managementCompanyVM);
This way doesn't work anymore. When I type AutoMapperMapper there is no Map method to call. What do I need to do to be able to access my mappings and use them?
public static MapperConfiguration Configure() {
MapperConfiguration mapperConfiguration = new MapperConfiguration(cfg => {
cfg.CreateMap<Ebill, EbillHarvesterTaskVM>()
cfg.CreateMap<Note, NoteVM>();
cfg.CreateMap<LoginItem, LoginCredentialVM>()
cfg.CreateMap<Login, ProviderLoginVM>()
});
return mapperConfiguration;
}
build the mapper and register it with the dependency container used by your application.
global.asax
MapperConfiguration config = AutoMapperConfig.Configure();;
//build the mapper
IMapper mapper = config.CreateMapper();
//..register mapper with the dependency container used by your application.
myContainer.Register<IMapper>(mapper); //...this is just an oversimplified example
Update your controllers to explicitly depend on the mapper via constructor injection
private readonly IMapper mapper;
public MyController(IMapper mapper, ...) {
this.mapper = mapper;
//...
}
And call the mapper as needed in the controller actions.
//...
Note model = mapper.Map<Note>(noteVM);
//...

How to mock dependencies for IValueResolver from Automapper in unit tests

After previous question I have a simple implementation of IValueResolver
public class FileLinkResolver : IValueResolver<Configuration, ConfigurationDto, string>
{
private readonly IFileStorage _fileStorage;
public FileLinkResolver(IFileStorage fileStorage)
{
_fileStorage = fileStorage;
}
public string Resolve(Configuration source, ConfigurationDto destination, string destMember, ResolutionContext context)
{
return _fileStorage.GetShortTemporaryLink(source.Path);
}
}
and simple mapping profile
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Configuration, ConfigurationDto>()
.ForMember(dest => dest.FilePath, opt => opt.MapFrom<FileLinkResolver>());
}
}
For production it works as expected when the following setup
services.AddTransient<IFileStorage>(...);
services.AddAutoMapper();
is used and then in controller IMapper is injected.
In unit test I try to stub the mapper
var mapperStub = new Mapper(new MapperConfiguration(map => map.AddProfile(new MappingProfile())));
and when I run tests for method witch should return mapped dto, I got
AutoMapper.AutoMapperMappingException : Error mapping types.
Mapping types:
Configuration -> ConfigurationDto
DataAccess.Models.Configuration -> Dto.ConfigurationDto
Type Map configuration:
Configuration -> ConfigurationDto
DataAccess.Models.Configuration -> Dto.ConfigurationDto
Destination Member:
FilePath
---- System.MissingMethodException : No parameterless constructor defined for this object.
I've tried to add parameterless constructor to FileLinkResolver but then, NullReferenceException
This is the question: how to resolve dependencies for ValueResolver
In the current example, the mapper is unable to resolve IFileStorage dependency when testing.
Change the way the mapper is created to more closely match how it is done at run-time.
IServiceCollection services = new ServiceCollection();
//mocking service using MOQ
var mock = Mock.Of<IFileStorage>(_ =>
_.GetShortTemporaryLink(It.IsAny<string>()) == "fake link"
);
//adding mock to service collection.
services.AddTransient<IFileStorage>(sp => mock);
//adding auto mapper with desired profile;
services.AddAutoMapper(typeof(MappingProfile));
//...add other dependencies as needed to service collection.
//...
//build provider
IServiceProvider serviceProvider = service.BuilderServiceProvider();
//resolve mapper
IMapper mapperStub = serviceProvider.GetService<IMapper>();
//Or resolve subject under test where mapper is to be injected
SubjectClass subject = serviceProvider.GetService<SubjectClass>();
//assuming ctr: public SubjectClass(IMapper mapper, .....) { ... }
Now technically this is not mocking the value resolver. It mocks the dependencies of the resolver, and uses an actual resolver from the profile. But this should provide the desired behavior when testing the target.

How to use Automapper with Autofac

I've upgraded to the latest version of AutoMapper (9.0) and I've changed the static configuration to:
public static IMapper RegisterAutoMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<MyModel MyDto>;
//etc...
});
var mapper = config.CreateMapper();
return mapper;
}
Using the previous static API I used to do the following in Global.asax:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
AutoMapping.Map();
}
WebApiConfig.Register registers the routes and also Autofac
How do I register AutoMapper with Autofac because currently I'm getting compiler errors on such lines:
var myDto = Mapper.Map<MyModel>(model);
And the compiler error:
An object reference is required for the non-static field, method, or property 'Mapper.Map(object)'
Here's one I made earlier:
public class YourAutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//Also register any custom type converter/value resolvers
builder.RegisterType<CustomValueResolver>().AsSelf();
builder.RegisterType<CustomTypeConverter>().AsSelf();
builder.Register(context => new MapperConfiguration(cfg =>
{
cfg.CreateMap<MyModel MyDto>;
//etc...
})).AsSelf().SingleInstance();
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>()
.InstancePerLifetimeScope();
}
}
In the global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterModule<MyAutofacModule>();
// Register anything else needed
var container = builder.Build();
// MVC resolver
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// API Resolver
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
Then all you need to do is inject IMapper
There is also a nuget-package that does all of that for you.
All you need to do is to call an extension method on the ContainerBuilder and pass in the assemblies, that should be scanned for AutoMapper types.
var containerBuilder = new ContainerBuilder();
containerBuilder.AddAutoMapper(typeof(MvcApplication).Assembly);
// more registrations here
You can find it here. You can find an official example in the AutoMapper docs as well.
Edit: There are samples for ASP.NET Core and Console-Applications here.
While I'm not familiar with Autofac myself, here is a recent article that descibes how to set up injection for automapper with Autofac.
Goodluck!

AutoMapper 4.2 and Ninject 3.2

I'm updating a project of mine to use AutoMapper 4.2, and I'm running into breaking changes. While I seem to have resolved said changes, I'm not entirely convinced I've done so in the most appropriate way.
In the old code, I have a NinjectConfiguration, and an AutoMapperConfiguration class that are each loaded by WebActivator. In the new version the AutoMapperConfiguration drops out and I instead instance a MapperConfiguration directly in the NinjectConfiguration class where the bindings are happening, like so:
private static void RegisterServices(
IKernel kernel) {
var profiles = AssemblyHelper.GetTypesInheriting<Profile>(Assembly.Load("???.Mappings")).Select(Activator.CreateInstance).Cast<Profile>();
var config = new MapperConfiguration(
c => {
foreach (var profile in profiles) {
c.AddProfile(profile);
}
});
kernel.Bind<MapperConfiguration>().ToMethod(
c =>
config).InSingletonScope();
kernel.Bind<IMapper>().ToMethod(
c =>
config.CreateMapper()).InRequestScope();
RegisterModules(kernel);
}
So, is this the appropriate way of binding AutoMapper 4.2 using Ninject? It seems to be working so far, but I just want to make sure.
In before IMapper interface didn't existed in the library so you had to implement interface and class below and bound them as a singleton pattern.
public interface IMapper
{
T Map<T>(object objectToMap);
}
public class AutoMapperAdapter : IMapper
{
public T Map<T>(object objectToMap)
{
//Mapper.Map is a static method of the library!
return Mapper.Map<T>(objectToMap);
}
}
Now you simply bind library's IMapper interface to single instance of mapperConfiguration.CreateMapper()
The Problem with your code tho, you should use a single instance(or as Ninject says, a constant) bind.
// A reminder
var config = new MapperConfiguration(
c => {
foreach (var profile in profiles) {
c.AddProfile(profile);
}
});
// Solution starts here
var mapper = config.CreateMapper();
kernel.Bind<IMapper>().ToConstant(mapper);

How to inject AutoMapper with Autofac?

What is the proper way to inject AutoMapper to other layers?
I read this blog post , but this code cause exception below
An exception of type 'AutoMapper.AutoMapperMappingException' occurred in AutoMapper.dll but was not handled in user code
when try mapping in service layer.
List<StudentViewModel> list2 = _mapper.Map<List<StudentViewModel>>(list);
My AutoFac configuration like below:
public static class DependencyRegistration
{
public static void Config()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<TypeMapFactory>().As<ITypeMapFactory>();
builder.RegisterType<ConfigurationStore>().As<ConfigurationStore>().WithParameter("mappers", MapperRegistry.Mappers).SingleInstance();
builder.Register((ctx, t) => ctx.Resolve<ConfigurationStore>()).As<IConfiguration>().As<IConfigurationProvider>();
builder.RegisterType<MappingEngine>().As<IMappingEngine>();
//...
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
.netcore 3
Autofac 5.1.2
AutoMapper 9.0.0
AutoMapperProfiles -> My profile name
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AutoMapperProfiles>().As<Profile>();
builder.Register(c => new MapperConfiguration(cfg =>
{
foreach (var profile in c.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
}
It seems that you need to use the IConfiguration object that is registered in the container to create the maps like this:
var configuration = container.Resolve<IConfiguration>();
configuration.CreateMap<Student, StudentViewModel>();
I think that you should be doing this at the start of your application.
Here is a better way (IMO) to configure things in the Config method:
public static void Config()
{
var configuration_store = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
var mapping_engine = new MappingEngine(configuration_store);
configuration_store.CreateMap<Student, StudentViewModel>();
var builder = new ContainerBuilder();
builder.RegisterInstance(mapping_engine).As<IMappingEngine>();
//...
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
I am assuming in the last example, that your classes need access only to IMappingEngine (and not IConfiguration), since your should already setup all mappings in the Config method (or some other configuration method at application startup).

Categories

Resources