How use AutoMapper correctly in a layered architecture? - c#

How do I even use AutoMapper correctly in a layered architecture and where do I initialize it if my path described below is not correct?
There is a solution screenshot
for the sake of a common understanding :)
As you can see, there are DTO's, Models and ViewModels in different layers
I want a mapping from DAL to BLL and then to (console)PL and conversely
But I get
AutoMapper.AutoMapperMappingException: 'Missing type map configuration or unsupported mapping'
can't find any similar examples for me
Thanks in advance
Here is an example of how I connect AutoMapper for ViewModel->DTO mapping, maybe this is not the right way?
I have the same way AutoMapper is connected in BLL for mapping DTO->Model
private IMapper _mapper;
private readonly BLL.BookService _bookService;
public UiBookService(UserDTO currentUser)
{
_mapper = new MapperConfiguration(cfg => cfg.CreateMap<BookViewModel, BookDTO>()).CreateMapper();
_bookService = new BLL.BookService(currentUser);
CurrentUser = currentUser;
}
then use it like this
await _bookService.CreateBook(_mapper.Map<BookDTO>(book));
BLL.BookService: (This is where this error occurs)
public async Task CreateBook(BookDTO book)
{
book.OwnerId = _currentUser.Id;
await _bookRepo.CreateAsync(_mapper.Map<Book>(book));
}
In this UiBookService, we create a BookViewModel from the console and pass it as BookDTO to BookService from BLL.
The strange thing is that in DTO the mapping goes fine, but in BLL it doesn't map from DTO to a normal Model

I would create two MappingConfig files.
Model <-> DTO in BLL.Mapping
DTO <-> ViewModel in PL.Mapping
This will allow you to test your mappings and use one mapping for the same signature among the whole program. Also, make sure that all mappings between entities are configured.
After that, inject them in a DI container.

Related

AutoMapper: Mapping between DTO and Entity

I am working with a ASP.NET Core WebAPI and I want to do CRUD for my objects called "Item".
I am using EF Core to work with a SQL Database and I have two models that represents my objects.
ItemDto - Data Transfer Object for an Item
ItemEntity - Database Object (represents a row in a table 1:1)
My HTTP GET one and HTTP GET many methods works in such way that it
Get ItemRepository instance
Fetch one or more ItemEntity
Map it to ItemDto by using AutoMapper
This is initalized in my constructor such as
m_itemDtoMapper = new Mapper(new MapperConfiguration(cfg => cfg.CreateMap<ItemEntity, ItemDto>()));
And in my WebAPI method I map it to a ItemDto with the following line (for the GET many case):
var itemDtos = m_itemDtoMapper.Map<IEnumerable<ItemEntity>, ICollection<ItemDto>>(items);
This works well and the AutoMapper is very powerful. The questions I have now is:
Is this the standard way of managing the relationship between database entities and data transfer objects?
In the CreateItem method, I need to do reverse mapping. Instead of mapping ItemEntity to ItemDto, I need to map a ItemDto to an ItemEntity. How shall I do this? Creating a copy of my mapper just with switched entities works but is that how its supposed to be done? i.e two mappers.
In your example, it seems that you initialize each time a new mapper instance. I would suggest you go along with dependency injection and make use of AutoMapper Mapping Profiles.
You can do it in three simple steps and I think it answers both of your questions:
Step 1:
Simply create a new class called MappingProfile or something similar:
public class MappingProfile: Profile
{
public MappingProfile()
{
CreateMap<User, AuthenticateDto>(); // One Way
CreateMap<User, UserDto>().ReverseMap(); // Reverse
}
}
Step 2: Register Automapper in Startup.cs
// Register AutoMapper
services.AddAutoMapper(Assembly.GetExecutingAssembly());
Step 3: Consume your mapper over DI
public UserService(IMapper mapper) {
_mapper = mapper;
}
// call it as you already did
_mapper.Map<User, UserDto>(user);
Hopefully it helps you :)

How to trigger AutoMapper to map a model using linq syntax?

I am trying to use AutoMapper 6.3 to allow me to auto map my model into viewmodels.
First I registered my AutoMapper instance to my IUnitContainer like so
var mapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile<AutoMapperProfile>();
});
container.RegisterInstance<IMapper>(mapper.CreateMapper());
Now, in my controller, I want to pull a model from the database, then I want to map/cast it to my view-model.
I tried to do the following
var task = UnitOfWork.Tasks.Get(123)
.ProjectTo<TaskViewModel>();
But I can't seems to find the ProjectTo extension which I assumed it will be part of the AutoMapper project.
What is the correct way to project the viewModel if my AutoMapperProfile already created the mapping?
It seems to be in Automapper.QueryableExtensions:
https://github.com/AutoMapper/AutoMapper/blob/8dd104aa7390c12c97c4195cce6f6ff66de24f51/src/AutoMapper/QueryableExtensions/Extensions.cs
you can call it as long as the previous item in your linq change is IQueryable it seems.

ViewModels or RequestModels in WebApi project and additional layer of mapping with automapper

I have Api project, business project and database context.
I am thinking of design like this:
viewmodels in api project, and mappings with automapper. Automapper
will here map viewmodel to business dto model
dto models in business project, and mappings with automapper. Automapper will here map dto model to entity model (database).
Question 1: Should I use OperationViewModel or OperationRequestModel(ResponseModel) in api project?
Question 2: Is additional mapping between viewmodel and dto model overkill, or is it good practice to separate those concerns and decouple even more, or should I map dto models with entity models and use those dto models in api project?
Firstly, I would like to congratulate you on 'getting it'. So many projects I see have the database access in the UI layer!!
Initially, you may feel that having different (but almost identical) classes for ViewModel, Business and data layers a pain, but this is where AutoMapper is brilliant. Most of the time, you don't need to do anything and it just works.
Once your code gets a bit more meat on the bone, you will find it easier to add database fields without having to worry about the effects on your view model, and to create view models that are exactly what the view requires, without having to worry about database fields. Win-win. I would also create a separate view model for each function, even if they are identical (use inheritance if required, but make sure you have a different class each time).
IMO, the models should be exposed by the layer that creates and consumes them, so the ViewModel should have XXXViewModel, the businesss layer have XXXDto etc.
public IndexViewModel Index()
{
var vm = new IndexViewModel()
{
Items = _mapper.map<List<Item>>(_service.GetSomeData())
};
return vm;
}
public GetViewModel Get(int id)
{
var vm = _mapper.Map<GetViewModel>(_service.get(id));
return vm;
}

Best Design Pattern implementation to convert different objects derived from the same interface

I have several objects as shown in the UML diagram below:
I have written a single page MVC application which handles all objects derived from the same interfce and differ in a few properties only. My model is the coverage of all possible properties.
The thing is that when I post data to DAL I must use entites, not Models. My Controller and View uses Model, but DAL methods expect either Entity A or Entity B.
Now I want to design a class to make appropriate coversions. I can make a class having methods ConvertToA() and ConvertToB() and call methods of this class. This is the most basic layout which comes to mind at first.
But is there an appropriate Design Pattern for this, or what could be the most flexible and efficient way to accomplish this task?
Regards.
You could use AutoMapper for object to object conversion. In your above mentioned case, a POST action would look like below:
[HttpPost]
public ActionResult TestAction(Model model)
{
var entityA = _mappingService.Map<Model, EntityA>(model);
testService.TestMethod(entityA);
return View();
}
You need to define mapping something like this for each Model -> ViewModel mapping (and viceversa):
Mapper.CreateMap<EntityA, Model>();
Mapper.CreateMap<Model, EntityA>();
if the objects are compatible, the conversion is supported. You could also configure mapping of individual object properties like:
Mapper.CreateMap<Order, OrderViewModel>()
.ForMember(o => o.OrderDescription, b => b.MapFrom(z => z.Description))
.ForMember(o => o.OrderId, b => b.MapFrom(z => z.Id));

Entity Framework + Autofac: How to properly reload mappings / configurations?

BACKGROUND:
Our core framework loads all entity framework mappings from itself, the main application and any modules we have installed by using an interface (below):
public interface IEntityTypeConfiguration : IDependency
{
}
and we have a DbContext in our core framework like this, which loads all the mappings:
public class DefaultDbContext : DbContextBase
{
private readonly Lazy<IEnumerable<IEntityTypeConfiguration>> configurations;
public DefaultDbContext(Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base()
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
public DefaultDbContext(string connectionString, Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base(connectionString)
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (dynamic typeConfiguration in configurations.Value)
{
modelBuilder.Configurations.Add(typeConfiguration);
}
Database.SetInitializer(new CreateTablesIfNotExist<DefaultDbContext>());
}
}
So this way we have a single DbContext for everything.
PROBLEM:
We've run into an issue whereby when we dynamically add new modules (which have their own mappings), then EF does not load those mappings ever, even when we are sure that a new instance of DefaultDbContext has been created. So, it must be that EF is cacheing the mappings somewhere. Is there some way to clear the cache?
FINAL NOTE:
As you may have guessed, we are using an IoC, namely Autofac. If you need any further info, just ask.
Any ideas, anyone?
The model is cached for performance reasons.
The following excerpt explains what is going on
Model Caching
There is some cost involved in discovering the model, processing Data Annotations and applying fluent API configuration. To avoid incurring this cost every time a derived DbContext is instantiated the model is cached during the first initialization. The cached model is then re-used each time the same derived context is constructed in the same AppDomain.
This text also mentions a property called CacheForContextType but this didn't make it into the final release of EF5.
This second link provides a glimmer of hope but again is dated before the final release of EF5
We removed CacheForContextType in CTP5, we originally intended it to be used when folks wanted to use the same context in the same AppDomain with different models. The issue is that it would create the model on every initialization and didn't allow any way to cache a series of models and choose which one to use during each initialization. Model creation is expensive so we wanted to promote a better pattern.
The pattern we recommend is to externally create a ModelBuilder -> DbDatabaseMapping -> DbModel for each model you want to use. The DbModel should be cached and used to create context instances. The ModelBuilder -> DbModel workflow is a little messy and the class names aren't great, they will be tidied up for RTM.
Personally I think you're going to have to find a way of knowing all of your models up front ...
Solved! We found this constructor on the DbContext class:
public DbContext(string nameOrConnectionString, DbCompiledModel model);
I can't share all of the code here, but basically we're creating a new DbCompiledModel and passing that in whenever necessary.

Categories