IEntityMapperEntityMapperBase is provided with support for AfterMappersEntityAfterMapperBase is provided// interface
public interface IEntityAfterMapper
{
bool CanMap(object source);
void AfterMap(object source, object target);
}
public interface IEntityAfterMapper<in TSource, in TTarget> : IEntityAfterMapper
{
void AfterMap(TSource source, TTarget target);
}
// base class
public abstract class EntityAfterMapperBase<TSource, TTarget> : IEntityAfterMapper<TSource, TTarget>
{
public abstract void AfterMap(TSource source, TTarget target);
public bool CanMap(object source)
}
When using Mapster (options.UseMapsterMapping()), the explicit UseMapping<>() and AddMapping<>() statements can be omitted. Mapster maps entities to and from their DTOs by convention, so as long as the entity and its DTOs share a similar structure (matching property names and types), the DTO type arguments on the controller are enough — no per-entity mapping registration is required.
You only need the explicit statements when:
e.UseMapping<TDto, TInputDto>().After(...) / .AfterInput(...), ore.AddMapping<TSource, TTarget>().AutoMapper (
options.UseAutoMapper()) does not map by convention: every entity ↔ DTO pair must be registered explicitly (eachUseMapping<>()/AddMapping<>()call performs aCreateMap). Without it, AutoMapper throws a missing-type-map error.
Both UseMapsterMapping(...) and UseAutoMapper(...) accept an optional callback to configure the underlying engine globally:
// Mapster — receives the shared TypeAdapterConfig
options.UseMapsterMapping(config =>
{
config.Default.IgnoreNullValues(true);
config.NewConfig<Order, OrderDto>()
.Map(dto => dto.Total, order => order.Lines.Sum(l => l.Price));
});
// AutoMapper — receives the IServiceProvider and the IMapperConfigurationExpression
options.UseAutoMapper((sp, cfg) =>
{
cfg.AddProfile<OrderMappingProfile>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dto => dto.Total, opt => opt.MapFrom(o => o.Lines.Sum(l => l.Price)));
});
Defaults applied by Regira (don’t re-set these unless you mean to):
PreserveReference(true) on the default config to prevent infinite recursion on circular references.AllowNullCollections = true and scans no profile assemblies automatically — register profiles and maps through this callback or the per-entity UseMapping<>() / AddMapping<>() statements.Multiple
UseEntities<TContext>()stacks each callingUseMapsterMapping()share oneTypeAdapterConfig, so every context’s entity ↔ DTO mappings apply regardless of registration order. Theconfiguredelegates run eagerly in call order — the last call wins on conflicting settings.
services
.UseEntities<MyDbContext>(options => {
// ...
options.UseMapsterMapping();
// or
options.UseAutoMapper();
// global AfterMapper — register a class implementing IEntityAfterMapper<TSource, TTarget>
options.AddAfterMapper<MyAfterMapper>();
// ...or inline, without a dedicated class:
options.AfterMap<MyModel, MyDto>((source, dto) => { /*...*/ });
})
.For<Order>(e =>
{
// ...
// With Mapster this UseMapping<>() is only needed for the After/AfterInput hooks;
// the Order <-> OrderDto/OrderInputDto mapping itself works by convention.
e.UseMapping<OrderDto, OrderInputDto>()
.After((item, dto) => { /*...*/ })
.AfterInput((dto, item) => { /*...*/ });
// extra mapping config (only required when convention isn't enough, or for AutoMapper)
e.AddMapping<OrderItem, OrderItemDto>();
e.AddMapping<OrderItemInputDto, OrderItem>();
});