Mapper configuration
The MapperAttribute
provides options to customize the generated mapper class.
Default Mapper configuration
The MapperDefaultsAttribute
allows to set default configurations applied to all mappers on the assembly level.
[assembly: MapperDefaults(EnumMappingIgnoreCase = true)]
Copy behavior
By default, Mapperly does not create deep copies of objects to improve performance.
If an object can be directly assigned to the target, it will do so
(eg. if the source and target type are both Car[]
, the array and its entries will not be cloned).
To create deep copies, set the UseDeepCloning
property on the MapperAttribute
to true
.
[Mapper(UseDeepCloning = true)]
public partial class CarMapper
{
...
}
Properties / fields
On each mapping method declaration, property and field mappings can be customized.
If a property or field on the target has a different name than on the source, the MapPropertyAttribute
can be applied.
See also the documentation on flattening / unflattening.
[Mapper]
public partial class CarMapper
{
[MapProperty(nameof(Car.Model), nameof(CarDto.ModelName))]
public partial CarDto ToDto(Car car);
}
Mapping from source
The source object itself can be mapped to a property of the target object with the MapPropertyFromSource
attribute:
[Mapper]
public partial class CarMapper
{
[MapPropertyFromSource(nameof(CarChanges.OriginalCar))]
public partial CarChanges ToChanges(Car car);
}
Ignore properties / fields
To ignore a property or field, the MapperIgnoreTargetAttribute
or MapperIgnoreSourceAttribute
can be used.
[Mapper]
public partial class CarMapper
{
[MapperIgnoreTarget(nameof(CarDto.MakeId))]
[MapperIgnoreSource(nameof(Car.Id))]
public partial CarDto ToDto(Car car);
}
Ignore a member at definition
To ignore a property or field at definition, the MapperIgnoreAttribute
can be used.
public partial class CarMapper
{
public partial CarDto ToDto(Car car);
}
public class Car
{
[MapperIgnore]
public int Id { get; set; }
public string ModelName { get; set; }
}
public class CarDto
{
public string ModelName { get; set; }
}
If you want to use the MapperIgnoreAttribute
in another .NET Project than the Mapper itself,
that project needs to preserve the Mapperly attributes at runtime,
see preserving Mapperly attributes at runtime.
Without this, the MapperIgnoreAttribute
is not visible to Mapperly.
Ignore obsolete members
By default, Mapperly will map source/target members marked with ObsoleteAttribute
.
This can be changed by setting the IgnoreObsoleteMembersStrategy
of a method with MapperIgnoreObsoleteMembersAttribute
,
or by setting the IgnoreObsoleteMembersStrategy
option of the MapperAttribute
.
Name | Description |
---|---|
None | Will map members marked with the Obsolete attribute (default) |
Both | Ignores source and target members with the Obsolete attribute |
Source | Ignores source members with the Obsolete attribute |
Target | Ignores target members with the Obsolete attribute |
- Global (mapper level)
- Local (mapping method level)
Sets the IgnoreObsoleteMembersStrategy
for all methods within the mapper,
by default it is None
allowing obsolete source and target members to be mapped.
This can be overriden by individual mapping methods using MapperIgnoreObsoleteMembersAttribute
.
[Mapper(IgnoreObsoleteMembersStrategy = IgnoreObsoleteMembersStrategy.Both)]
public partial class CarMapper
{
...
}
Method will use the provided ignore obsolete mapping strategy,
otherwise the MapperAttribute
property IgnoreObsoleteMembersStrategy
will be used.
[Mapper]
public partial class CarMapper
{
[MapperIgnoreObsoleteMembers(IgnoreObsoleteMembersStrategy.Both)]
public partial CarMakeDto MapMake(CarMake make);
}
Property name mapping strategy
By default, property and field names are matched using a case sensitive strategy.
If all properties/fields differ only in casing, for example ModelName
on the source
and modelName
on the target,
the MapperAttribute
can be used with the PropertyNameMappingStrategy
option.
[Mapper(PropertyNameMappingStrategy = PropertyNameMappingStrategy.CaseInsensitive)]
public partial class CarMapper
{
public partial CarDto ToDto(Car car);
}
public class Car
{
public string ModelName { get; set; }
}
public class CarDto
{
public string modelName { get; set; }
}
null
values
Mapperly allows the customization of how null
values are handled when mapping properties.
AllowNullPropertyAssignment
allows to configure whether null
values are assigned to nullable target properties.
If it is true
and the source value is null
, the target property is explicitly set to null
.
If it is false
, the property mapping is ignored or an exception is thrown,
depending on the value of ThrowOnPropertyMappingNullMismatch
.
AllowNullPropertyAssignment
is true
by default.
ThrowOnPropertyMappingNullMismatch
controls how null
source values are handled,
if the target property is not nullable or AllowNullPropertyAssignment
is set to false
.
If ThrowOnPropertyMappingNullMismatch
is enabled, an ArgumentNullException
is thrown.
If ThrowOnPropertyMappingNullMismatch
is disabled, the property mapping is ignored.
ThrowOnPropertyMappingNullMismatch
is false
by default.
For mapping methods the behaviour can be specified via ThrowOnMappingNullMismatch
.
When the mapper tries to return a null
value from a mapping method with a non-nullable return type,
and ThrowOnMappingNullMismatch
is set to false
,
Mapperly tries to return a default value.
For strings the default value is the empty string,
for value types, it is default
,
for reference types with a public parameterless constructor, a new instance is created.
If no such constructor exists an ArgumentNullException
is thrown.
If ThrowOnMappingNullMismatch
is true
(default), an ArgumentNullException
is thrown.
AllowNullPropertyAssignment
, ThrowOnPropertyMappingNullMismatch
and ThrowOnMappingNullMismatch
are ignored for required init properties and IQueryable<T>
projection mappings.
One side strict property mappings
By default Mapperly emits diagnostics with a severity of warning if there are unmapped source or target members.
To enforce strict mappings on only either the source or the target,
the RequiredMappingStrategy
can be used.
- Global (mapper level)
- Local (mapping method level)
Sets the RequiredMappingStrategy
for all methods within the mapper,
by default it is Both
requiring all members to be mapped.
This can be overriden by individual mapping methods using MapperRequiredMappingAttribute
.
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Source)]
public partial class CarMapper
{
...
}
Applied to the specific mapping method.
[Mapper]
public partial class CarMapper
{
[MapperRequiredMapping(RequiredMappingStrategy.Source)]
public partial CarDto MapCar(Car car);
}
String format
The string format passed to ToString
calls when converting to a string can be customized
by using the StringFormat
property of the MapPropertyAttribute
.
[Mapper]
public partial class CarMapper
{
[MapProperty(nameof(Car.Price), nameof(CarDto.Price), StringFormat = "C")]
public partial CarDto MapCar(Car car);
}
String format provider & culture
To customize the format provider / culture to be used by Mapperly when calling ToString
format providers can be used.
A format provider can be provided to Mapperly by simply annotating a field or property within the Mapper with the FormatProviderAttribute
.
The field/property need to return a type implementing System.IFormatProvider
.
Format providers can be referenced by the name of the property / field in MapPropertyAttribute.FormatProvider
.
A format provider can be marked as default (set the default property of the FormatProviderAttribute
to true).
A default format provider is used for all ToString
conversions
when the source implements has a ToString
overload accepting a System.IFormatProvider
.
In a mapper only one format provider can be marked as default.
[Mapper]
public partial class CarMapper
{
[FormatProvider(Default = true)]
private IFormatProvider CurrentCulture => CultureInfo.CurrentCulture;
[FormatProvider]
private readonly IFormatProvider _enCulture = CultureInfo.GetCultureInfo("en-US");
[MapProperty(nameof(Car.LocalPrice), nameof(CarDto.LocalPrice), StringFormat = "C")]
[MapProperty(nameof(Car.ListPrice), nameof(CarDto.ListPrice), StringFormat = "C", FormatProvider = nameof(_enCulture)]
public partial CarDto MapCar(Car car);
// generates
target.LocalPrice = source.LocalPrice.ToString("C", CurrentCulture);
target.ListPrice = source.ListPrice.ToString("C", _enCulture);
}
User-implemented property mappings
To use a custom implemented mapping for a specific property or field,
the Use
property of the MapProperty
attribute can be used.
Set it to a unique name of a user-implemented mapping method.
The use of nameof
is encouraged.
See also user-implemented mapping methods.
- enabled AutoUserMappings (default)
- disabled AutoUserMappings
[Mapper]
public partial class CarMapper
{
[MapProperty(nameof(Car.Price), nameof(CarDto.Price), Use = nameof(MapPrice))]
public partial CarDto MapCar(Car source);
// set Default = false to not use it for all decimal => string conversions
// if using AutoUserMappings = false, the UserMapping is not needed.
[UserMapping(Default = false)]
private string MapPrice(decimal price)
=> (price / 100).ToString("C");
// generates
target.Price = MapPrice(source.Price);
}
[Mapper(AutoUserMappings = false)]
public partial class CarMapper
{
[MapProperty(nameof(Car.Price), nameof(CarDto.Price), Use = nameof(MapPrice))]
public partial CarDto MapCar(Car source);
private string MapPrice(decimal price)
=> (price / 100).ToString("C");
// generates
target.Price = MapPrice(source.Price);
}
User-implemented mapping from source
The Use
property can also be assigned on the MapPropertyFromSource
attribute, for example to access multiple properties of the source in the mapping method:
[Mapper]
public partial class CarMapper
{
[MapPropertyFromSource(nameof(CarDto.NetPrice), Use = nameof(MapPrice))]
public partial CarDto MapCar(Car source);
private decimal MapPrice(Car car)
=> car.Price - car.Discount;
// generates
target.NetPrice = MapPrice(source);
}