How to set up Automapper in ASP.NET Core
I figured it out! Here's the details:
Add the main AutoMapper Package to your solution via NuGet.
Add the AutoMapper Dependency Injection Package to your solution via NuGet.
Create a new class for a mapping profile. (I made a class in the main solution directory called
MappingProfile.cs
and add the following code.) I'll use aUser
andUserDto
object as an example.public class MappingProfile : Profile {
public MappingProfile() {
// Add as many of these lines as you need to map your objects
CreateMap<User, UserDto>();
CreateMap<UserDto, User>();
}
}Then add the AutoMapperConfiguration in the
Startup.cs
as shown below:public void ConfigureServices(IServiceCollection services) {
// .... Ignore code before this
// Auto Mapper Configurations
var mapperConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mapperConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddMvc();
}To invoke the mapped object in code, do something like the following:
public class UserController : Controller {
// Create a field to store the mapper object
private readonly IMapper _mapper;
// Assign the object in the constructor for dependency injection
public UserController(IMapper mapper) {
_mapper = mapper;
}
public async Task<IActionResult> Edit(string id) {
// Instantiate source object
// (Get it from the database or whatever your code calls for)
var user = await _context.Users
.SingleOrDefaultAsync(u => u.Id == id);
// Instantiate the mapped data transfer object
// using the mapper you stored in the private field.
// The type of the source object is the first type argument
// and the type of the destination is the second.
// Pass the source object you just instantiated above
// as the argument to the _mapper.Map<>() method.
var model = _mapper.Map<UserDto>(user);
// .... Do whatever you want after that!
}
}
How to setup AutoMapper in ASP.Net Core 6
Using this line instead: typeof(Program).Assembly
How to configure AutoMapper in Asp.Net 5 Core app?
2 things are needed:
In the
Startup.cs
file:services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
You may create a folder for your mappings and call it
MappingProfiles
or anything you want. And then add your mapping profile classes, note, the class should inherit fromProfile
object of theAutoMapper
namespace and do the mappings in the constructor.public class UserProfile : Profile
{
CreateMap<UserViewModel, User>();
}
In your case, it doesn't work because you are doing the wrong mapping direction. You need to make it opposite.
Change to:
MapperExpression.CreateMap(typeof(UserViewModel), typeof(User));
AutoMapper doesn't work in asp net core 5.0.2
Recomended way of registering Autommaper is described in their docs: https://docs.automapper.org/en/stable/Dependency-injection.html#asp-net-core
Create mapping profile and register it using
services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
In your case looks like you registered mapper instance, your example says that you injected mapper instance but exception says that you want to resolve IConfiguration. Check your code, if you don't try to inject IConfiguration (which is not registered).
Configuring AutoMapper in ASP.NET Core
Only adding services.AddAutoMapper();
to the ConfigureServices
method would not work for you. You have to configure AutoMapper
as follows:
public void ConfigureServices(IServiceCollection services)
{
// Auto Mapper Configurations
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddMvc();
}
And also don't forget to install the AutoMapper.Extensions.Microsoft.DependencyInjection
nuget package.
How to initialize AutoMapper in a multi-layer web application based on ASP.NET Core 5?
If you really don't want to use dependency injection, you can handle this with a static bootstrapper class to setup the mappings and to access the mapper instance:
// DataAccess project
public static class MapperBootstrapper
{
private static IMapper _instance;
internal static IMapper Instance => _instance;
public static void Configure()
{
if (_instance != null)
throw new InvalidOperationException("Already configured");
var config = new MapperConfiguration(
cfg =>
{
cfg.AddProfile<ProjectProfile>();
// Add more profiles and other mapping
});
_instance = config.CreateMapper();
}
}
With profiles you can group your related mapping logic, such as mapping related to the Project
model:
// DataAccess project
public class ProjectProfile : Profile
{
public ProjectProfile()
{
CreateMap<ProjectEntity, Model.Project>()
.ForMember(
dest => dest.FullName,
opt => opt.MapFrom(src => $"{src.Area}\\{src.Name}"));
}
}
In your Startup.cs
you can then use the bootstrapper class to setup the mappings as early as possible in the application's lifecycle (if you don't want the WebApplication project to reference the DataAccess project, you'll need an intermediate class in the BusinessLogic project):
public void ConfigureServices(IServiceCollection services)
{
DataAccess.MapperBootstrapper.Configure();
// ...
}
In your ProjectDataAccessor
you can then use the mapper like so:
public List<Model.Project> GetProjects()
{
var dbCollection = // Get data from the source
return MapperBootstrapper.Instance
.Map<List<Model.Project>>(dbCollection);
}
The examples are based on some dummy models:
// DataAccess project
public class ProjectEntity
{
public Guid ID { get; set; }
public string Area { get; set; }
public string Name { get; set; }
}
// Model project
public class Project
{
public Guid ID { get; set; }
public string FullName { get; set; }
}
To see an example in action, check out this fiddle.
ASP.NET CORE Automapper Profile with Scoped Dependency
I'll answer my own question for future reference:
Thanks to @lucian-bargaoanu for providing the link in the comments: https://docs.automapper.org/en/latest/Queryable-Extensions.html#parameterization
Dynamic parameters can be passed via the ProjectTo method.
I ended up creating extension methods for all my DTO Projections
public static class DestinationProjection
{
public static IQueryable<Destination> ProjectToDestination(IQueryable source, IConfiguration configuration, int currentUserId) {
return source.ProjectTo<Destination>(configuration, new { currentUserId });
}
}
And in the mapping I used this parameter
public class MappingProfile : Profile
{
public MappingProfile() {
int? currentUserId = null;
CreateMap<Source, Destination>()
.ForMember(vm => vm.NumOwnComments, opts => opts.MapFrom(s => s.Comments.Count(c => c.UserId == currentUserId.GetValueOrDefault()))
;
}
}
This way I can inject my ICurrentUserService
in the handler class.
public class DestinationListQueryHandler
{
public DestinationListQueryHandler(IMapper mapper, IDbContext dbContext, ICurrentUserService currentUserService)
{
// field initialization logic
}
public async Task<IEnumerable<Destination>> Handle(CancellationToken cancellationToken)
{
return await dbContext.Sources.ProjectToDestination(mapper.ConfigurationProvider, currentUserId).ToListAsync(cancellationToken);
}
}
An issue with AutoMapper in ASP.Net Core
Ok, I've managed to solve the problem, it had nothing to do with the code above. Just passed the wrong assembly to the profile constructor
Using Automapper with ASP.NET Core
Mapper.AssertConfigurationIsValid();
This calls the static IMapper
instance which is used in situations where you don’t use dependency injection. Since you never set up the static mapper, using it there will fail.
What you want to do instead is call AssertConfigurationIsValid
on the actual mapper instance, the one that you are registering as a singleton. So you should remove the assert from the mapper profile and instead call it within your AddApplicationMappings
method:
IMapper mapper = mapperConfig.CreateMapper();
mapper.AssertConfigurationIsValid();
services.AddSingleton(mapper);
Related Topics
Parallel.Foreach Slower Than Foreach
Reading Excel File Using Oledb Data Provider
How to Filter "Include" Entities in Entity Framework
How to Fix "Referenced Assembly Does Not Have a Strong Name" Error
.Net Core 3.0 Possible Object Cycle Was Detected Which Is Not Supported
C# Thread Termination and Thread.Abort()
How to Call a Vbscript File in a C# Application
Invalid Attempt to Read When No Data Is Present
Redirecting Standard Input of Console Application
Multiple Parallel.Foreach Loops in .Net
How to Compare Two Rich Text Box Contents and Highlight the Characters That Are Changed
Console Application Closes Immediately After Opening in Visual Studio
C# Image Resizing to Different Size While Preserving Aspect Ratio
Addbusinessdays and Getbusinessdays
How to Get the Pid of the Parent Process of My Application
Export to Excel from a List with Epplus
How Enumerate All Classes with Custom Class Attribute
An Attempt Was Made to Access a Socket in a Way Forbidden by Its Access Permissions. Why