Reputation: 1114
Is there any way to auto-configue Automapper to scan for all profiles in namespace/assembly? What I would like to do is to add mapping profiles to AutoMapper from given assembly filtered by given interface, something like Scan Conventions in StructureMap:
public static void Configure()
{
ObjectFactory.Initialize(x =>
{
// Scan Assembly
x.Scan(
scanner =>
{
scanner.TheCallingAssembly();
scanner.Convention<MyCustomConvention>();
scanner.WithDefaultConventions();
});
// Add Registries
x.AddRegistry(new SomeRegistry());
});
Debug.WriteLine(ObjectFactory.WhatDoIHave());
}
public class MyCustomConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (!type.CanBeCastTo(typeof(IMyType)))
{
return;
}
string name = type.Name.Replace("SomeRubishName", String.Empty);
registry.AddType(typeof(IMyType), type, name);
}
I've tried to use SelfConfigure but can't find any documentation on how to use it to filter out profiles:
public static void Configure()
{
Mapper.Initialize(x =>
{
// My Custom profile
x.AddProfile<MyMappingProfile>();
// Scan Assembly
x.SelfConfigure(Assembly.GetCallingAssembly());
});
}
Another question is how can I report all maps/profiles already initialized (something like ObjectFactory.WhatDoIHave() in StructureMap)?
Upvotes: 29
Views: 44225
Reputation: 466
//AutoMapper 12.0.0
using Microsoft.Extensions.DependencyInjection;
//if the profiles are in the same assembly as the StartUp class
services.AddAutoMapper(typeof(Startup));
//else
services.AddAutoMapper(typeof(AnyProfile));
Upvotes: 2
Reputation: 79
Just to add to @Rosco answer you can use typeof(class) instead of assembly. Any class will work.
services.AddAutoMapper(typeof(Startup));
Then you do not need to add Reflection reference.
If you have Profiles in multiple assemblies, you can use it like this.
services.AddAutoMapper(typeof(Startup), typeof(User));
Upvotes: 1
Reputation: 2474
In version 9 of AutoMapper it can be done this way
var configuration = new MapperConfiguration(cfg =>
{
// Add all Profiles from the Assembly containing this Type
cfg.AddMaps(typeof(MyApp.SomeClass));
});
If you are using ASP.NET Core there is a helper extension to register all Profiles in Startup.ConfigureServices
// UI project
services.AddAutoMapper(Assembly.GetExecutingAssembly());
or
// Another assembly that contains a type
services.AddAutoMapper(Assembly.GetAssembly(typeof(MyApp.SomeClass)));
Upvotes: 23
Reputation: 141
In .NET Core:
services.AddSingleton(this.CreateMapper());
//...
private IMapper CreateMapper()
=> new MapperConfiguration(config => config.AddMaps(Assembly.Load("Your.Project.App")))
.CreateMapper();
Upvotes: 2
Reputation: 870
Similar to @Martino's answer, but with a MapperConfiguration object. This will add all profiles from the assembly that contains the type MyProfile.
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfiles(typeof(MyProfile));
});
var mapper = config.CreateMapper();
Upvotes: 1
Reputation: 1471
In the latest versions of AutoMapper it's possible to register multiple Profile scanning one or more assemblies :
Mapper.Initialize(x => x.AddProfiles(typeof(MyMappingProfile).Assembly));
Tested with AutoMapper v. 6.0.2.0
Upvotes: 19
Reputation: 1
public class AutoMapperAdapter : IMapper
{
private readonly MapperConfigurationExpression _configurationExpression =
new MapperConfigurationExpression();
public void AssertConfigurationIsValid() { Mapper.AssertConfigurationIsValid(); }
public void CreateMap<TSource, TDestination>()
{
_configurationExpression.CreateMap<TSource, TDestination>();
}
public void Initialize() { Mapper.Initialize(_configurationExpression); }
public TDestination Map<TDestination>(object source)
{
return Mapper.Map<TDestination>(source);
}
}
Upvotes: 0
Reputation: 7073
I found this post while searching as well, but this is how I implemented an auto mapping scheme:
public class MyCustomMap : Profile
{
protected override void Configure()
{
CreateMap<MyCustomViewModel, MyCustomObject>()
.ForMember(dest => dest.Phone,
opt => opt.MapFrom(
src => src.PhoneAreaCode + src.PhoneFirstThree + src.PhoneLastFour));
}
}
public static class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x => GetConfiguration(Mapper.Configuration));
}
private static void GetConfiguration(IConfiguration configuration)
{
var profiles = typeof(MyCustomMap).Assembly.GetTypes().Where(x => typeof(Profile).IsAssignableFrom(x));
foreach (var profile in profiles)
{
configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
}
}
}
So when my application starts, all I call is
AutoMapperConfiguration.Configure();
And all my maps are registered.
Upvotes: 41
Reputation: 17627
I have it like this, don't know if it is the best way but it works very well on pretty large project.
public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
private AutoMapper.IConfiguration _configuration;
public AutoMapperGlobalConfiguration(IConfiguration configuration)
{
_configuration = configuration;
}
public void Configure()
{
//add all defined profiles
var query = this.GetType().Assembly.GetExportedTypes()
.Where(x => x.CanBeCastTo(typeof(AutoMapper.Profile)));
_configuration.RecognizePostfixes("Id");
foreach (Type type in query)
{
_configuration.AddProfile(ObjectFactory.GetInstance(type).As<Profile>());
}
//create maps for all Id2Entity converters
MapAllEntities(_configuration);
Mapper.AssertConfigurationIsValid();
}
private static void MapAllEntities(IProfileExpression configuration)
{
//get all types from the SR.Domain assembly and create maps that
//convert int -> instance of the type using Id2EntityConverter
var openType = typeof(Id2EntityConverter<>);
var idType = typeof(int);
var persistentEntties = typeof(SR.Domain.Policy.Entities.Bid).Assembly.GetTypes()
.Where(t => typeof(EntityBase).IsAssignableFrom(t))
.Select(t => new
{
EntityType = t,
ConverterType = openType.MakeGenericType(t)
});
foreach (var e in persistentEntties)
{
var map = configuration.CreateMap(idType, e.EntityType);
map.ConvertUsing(e.ConverterType);
}
}
}
}
Upvotes: 1
Reputation: 26765
Yeah, that would be fantastic...and exactly what I'm overhauling for V2. Scanning, registration, conventions etc.
There's not a good "What do I have" feature, but I think it would definitely be worth adding.
Upvotes: 9