Great series. I love the way he has this internal dialog with Copilot with "YES!" and seems really impressed with it. A bit like a proud dad. I can sometimes hear a smile. Funny :)
I have a fundamental issue with these mapping libraries. If object mapping is complicated, we run into these weird config statements that are library specific. You will inevitably have to debug some mapping issue that is buried in a library code. In these situations, I would prefer to manually map it. If the mapping is simple, the mapping library doesn't add any real value and I would prefer to manually map it. AutoMapper/Mapster is one of the very vew libraries I do not find a ton of value in. Having said that, this is another outstanding video Amichai. Thank you for this series!!
@@amantinband Is there a way to map only not default values? Like.. ignore 0's and nulls? Thats a huge problem isnt it? When an object come with some null values and they replace not null values
There are two sides to everything. When you have some complicated mapping, you should definitely write unit tests for them to be sure the mapping is correct.
Mapping through Mapster/Automapper might be quite volatile. On the early stages of the project we can make sure that if a model needs special mapping, the profile will be added. But after few years, when one model changes it might be very easy to omit/forget to update/provide new mapping profile. This tutorial could really use a glimpse into testing mapping, either through unit tests or integration (?) tests and how to prevent mapping exceptions being discovered at runtime. Especially it could use some good techinques/best practices how to maintain those profiles as the project grows, team members come and go, scopes change etc.
💯. The main issue with mappers (other than the initial learning curve) is runtime exceptions. I edited out the part where I talk about unit tests, but perhaps I should have at least mentioned it in the final version. Unit tests are a must, whether the objects are manually mapped or mapped via some mapper.
I am really grateful for this series. Being used to using Automapper, but i will play around with Mapster. Have to catch with up latest video, and waiting for more.
Mappings sometimes is really painfull... Thanks for the tips! I'm working in a project and trying to implement validations in the most cleaner way... I hope you talk about it really soon :D
Please, I really need some help! Already lost two days with this issue: I got an inputmodel "OrderRequest" with two attributes: string itemCode, List orders. I'm trying to map it to a list of Order entities and get the same itemCode on all of them. Like this: Controller: _mapper.Map(request); Mapping: config.NewConfig() .Map(dest => dest, src => src.itemCode) .Map(dest => dest, src => src.orders.Adapt()); I get nothing... Empty list. What am I doing wrong? I've tried everything. I'm almost giving up on Mapster. I tried googling it but theres almost nothing about mapster... BTW i'm using mapster to get back a response from an entity and it works. Configurations are working. Thanks a lot for any help!
@@amantinband Excellent. Following along with Part 8 now, albeit my own schema and adapting as we go. A more hands-on approach to learning by applying to a project immediately :)
Junior dev here, I'm probably missing something, I can't help it but ask: why do we need a mapping library? Regardless of the types being mapped (DTO, Domain, ViewModel, Request for CQRS handler etc.) each mapping happens in one and only one place in the app. So why is manual mapping considered so hard to do all of a sudden? Or if for some reason the mapping from type A to type B occurs in many places in the code (weird), then why not just implement conversion operator ?
Hey man great videos. This series is honestly the best I've seen so far. Any chance you can do some video(s) on proper logging middleware implementation and/or an audit trail with point-in-time rollback capabilities?
Great series Amichai, btw, I think a better approach for silencing the compiler would be to remove the async keyword at the first place, and in order to return a Task, just return Task.FromResult(any_object_here), this skips the overhead of adding the await/async state machine in IL.
This is still part of the series 🙂 After we get familiar with these libraries and the project structure we will revisit the client application and learn the various DDD concepts while implementing the core logic of the application
I like this sort of magic. Especially since manual mapping starts nice and clean but becomes quite complex over time. Is it better? Really depends on preference and team
I think Mapster also includes C# code generators so the mappings don't need to use reflection. Also, you may consider using code generation to do your Injection rather than assembly scanning as well. Maybe consider an installment on code generation.
Hey, Amichai! I am using the strongly typed IDs you introduced later (private constructor and public static factory method). In case I wanted to have strongly typed IDs on my Commands and Queries, how would the mapping from GUID to those IDs be configured? config.NewConfig() .Map(dest => dest.UserId, src => UserId.Create(src.UserId)); public record Command(UserId UserId, ...); This doesn't work as Mapster is looking for a constructor for UserId.
Every time I'm trying to make a Request I got error: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1] An unhandled exception has occurred while executing the request. System.ArgumentException: IDX10703: Cannot create a 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey', key length is zero.
Thank you for your work, it's awesome! I'm curious about mapping in application and infrastructure layers. Shouldn't we use DTOs in application layer to map them to entities in repository? Or is it just redundant work?
The repositories work with domain models. You can, of course, have a mapping layer from domain models to DTOs in your persistence logic. I think it's redundant when using EF Core since we can configure the mapping between the domain models and the actual storage, but we'll talk all about this in future videos 🙂
I like explicit Mappings, there was this great addon vsix called MappingGenerator but its creator unfortunately turned it into a paid extension of which the price is a bit steep…
For DDD I have a private default constructor on my target object with a public static factory method to create the object. Can I force Mapster to use the factory, as currently it throws an exception when it can't find the default constructor. How do you handle this?
It's been a while, but I found a solution. Let's say you want to map a GUID to a UserId with private constructor and public static factory method. config.NewConfig() .MapWith(src => UserId.Create(src)); config.NewConfig() .Map(dest => dest.UserId, src => src.UserId) .Map(dest => dest, src => src.Request);
Please anybody help me why i am getting this error "error CS0246: The type or namespace name 'IMapper' could not be found " . I have added below references
I can't get the Mapster to work in the minimal API:InvalidOperationException: Failure to infer one or more parameters. Below is the list of parameters that we found: Parameter | Source --------------------------------------------------------------------------------- request | Body (Inferred) mapper | UNKNOWN mediator | Services (Inferred)
can you speak more about this? what do you prefer to user? extension method ".Adapt()" or by dependency injection "IMapper" ? Is there any downside to using the extension method ".Adapt()". the code looks cleaner and more straightforward :D
Well, it depends on your mapping logic. If you have any dependencies, it may be useful to simply mock the mapping. An easy example is something like the following: config.NewConfig() .Map(dest => dest.Name, src => MapContext.Current.GetService().Format(src.Name));
@@iliyan-kulishev well Nick uses jetbrains Rider where that functionality already present.. i.e. downloading external code I am pretty sure its not present in VS Code by default so if you just know what extension Amichai is using we will be able to do it to
Haha funny thread 😂 I thought it came from the `ilspy-vscode` extension but I don't have it installed. I honestly don't remember how I configured this and I'm unable to reproduce it on my other machines ATM. Weird. I'll have to dig deeper
I dont know why, but code on line _mapper.Map(authResult) dont use defined map. Response has set only Token, but other properties are empty. I also try add BeforeMapping, but is not called.
Very well! How can I ignore null values from ? I'm in troubles 'cause Config .IgnoreNullValues(true) it's ok when ignoring string null values but When my source object have int?, datetime? or decimal? it full overwrite the destinaton values with null.
I think a digestible approach to break down the series is first getting CQRS, MediatR, Mapster, FluentValidation etc' out of the way together with the auth stuff. Then, we can revisit the client application, learn the various DDD concepts while implementing the core logic of the application. What do you think?
We use AutoMapper for mappings. Sometimes it's hard to find out what is wrong with the code.. This one looks like it's more forgiving. And you said it is faster, will check that out 😀
Сомнительно, но окэй... Стал ли код проще? Нет. Стал ли код эффективнее и быстрее? Нет. Может быть в некоторых случаях будет меньше строк кода, вот и весь профит...
Amichai Mantinband, 22:36 is await Task.CompletedTask better than return await ValueTask.FromResult()? Looks like crutch, just for enforce IDE to be silent about this.