Configuring data mapping
You may need to map data between some API types and Model types, known as DTO design pattern.
Apizr could handle it for you by providing an IMappingHandler
interface implementation to it.
Fortunately, there are some integration Nuget packages to do so.
Of course, you can implement your own integration, but here we'll talk about the provided ones.
Please first install this integration package of your choice:
Project | Current | Upcoming |
---|---|---|
Apizr.Integrations.AutoMapper | ||
Apizr.Integrations.Mapster |
Where:
- Apizr.Integrations.AutoMapper package brings an
IMappingHandler
implementation for AutoMapper - Apizr.Integrations.Mapster package brings an
IMappingHandler
implementation for Mapster
Defining
AutoMapper
As usually with AutoMapper, define your mapping profiles, like for example:
public class UserMinUserProfile : Profile
{
public UserMinUserProfile()
{
CreateMap<User, MinUser>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.FirstName));
CreateMap<MinUser, User>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.Name));
}
}
Mapster
No need to write your own DTO classes. Mapster provides Mapster.Tool to help you generating models. And if you would like to have explicit mapping, Mapster also generates mapper class for you.
[AdaptTo("[name]Dto"), GenerateMapper]
public class Student {
...
}
Then Mapster will generate:
public class StudentDto {
...
}
public static class StudentMapper {
public static StudentDto AdaptToDto(this Student poco) { ... }
public static StudentDto AdaptTo(this Student poco, StudentDto dto) { ... }
public static Expression<Func<Student, StudentDto>> ProjectToDto => ...
}
But you can also write your own mapping configuration, like for example:
TypeAdapterConfig<TSource, TDestination>
.NewConfig()
.Ignore(dest => dest.Age)
.Map(dest => dest.FullName,
src => string.Format("{0} {1}", src.FirstName, src.LastName));
Advanced
Warning
Data Mapping with MediatR and/or Optional
If you plan to use MediatR and/or Optional integrations, one more defining step has to be done.
Only for those of you planning to use data mapping with MediatR and/or Optional, Apizr provide a MappedWith
attribute telling it to map api object with model object.
You’ll find another MappedCrudEntity
attribute dedicated to CRUD apis, coming with auto-registration capabilities, in case of access restricted to only local client model.
We could get a model class mapped to an api one like:
[MappedWith(typeof(User))]
public class MinUser
{
public int Id { get; set; }
public string Name { get; set; }
}
Registering
AutoMapper
First create a MapperConfiguration
with your profiles:
var mapperConfig = new MapperConfiguration(config =>
{
config.AddProfile<UserMinUserProfile>();
config.AddProfile<WhateverProfile>();
});
Then you'll be able to register with this option:
// direct short configuration
options => options.WithAutoMapperMappingHandler(mapperConfig)
// OR direct configuration
options => options.WithMappingHandler(new AutoMapperMappingHandler(mapperConfig.CreateMapper()))
// OR factory configuration
options => options.WithMappingHandler(() => new AutoMapperMappingHandler(mapperConfig.CreateMapper()))
Mapster
Register with one of the following options:
// direct short configuration
options => options.WithMapsterMappingHandler(new Mapper())
// OR direct configuration
options => options.WithMappingHandler(new MapsterMappingHandler(new Mapper()))
// OR factory configuration
options => options.WithMappingHandler(() => new MapsterMappingHandler(new Mapper()))
Using
You can tell Apizr to map data just by providing types when executing a request.
Something like:
var result = await reqResManager.ExecuteAsync<MinUser, User>((api, user) =>
api.CreateUser(user, CancellationToken.None), minUser);
Here we give a MinUser typed object to Apizr, which will be mapped to User type just before sending it. Then Apizr will map the User typed result back to MinUser type just before returning it.
There are much more overloads so you can map objects the way you need. The same while using MediatR and/or Optional.