Compentio.SourceMapper 1.0.4-rc

This is a prerelease version of Compentio.SourceMapper.
There is a newer version of this package available.
See the version list below for details.
dotnet add package Compentio.SourceMapper --version 1.0.4-rc
NuGet\Install-Package Compentio.SourceMapper -Version 1.0.4-rc
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Compentio.SourceMapper" Version="1.0.4-rc" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Compentio.SourceMapper --version 1.0.4-rc
#r "nuget: Compentio.SourceMapper, 1.0.4-rc"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Compentio.SourceMapper as a Cake Addin
#addin nuget:?package=Compentio.SourceMapper&version=1.0.4-rc&prerelease

// Install Compentio.SourceMapper as a Cake Tool
#tool nuget:?package=Compentio.SourceMapper&version=1.0.4-rc&prerelease

How to use

To define mapping we have to mark mapping abstract class or interface with MapperAttribute:

[Mapper]
public interface INotesMapper
{
    NoteDto MapToDto(NoteDao source);
}

This will generate mapping class with default class name NotesMapper for properties that names are the same for NoteDto and NoteDao classes. The generated class is in the same namespace as its base abstract class of interface. It can be found in project in Visual Studio:

Dependencies → Analyzers → Compentio.SourceMapper.Generators.MainSourceGenerator.

When the names are different than we can use Source and Target names of the properties:

[Mapper(ClassName = "InterfaceUserMapper")]
public interface IUserMapper
{
    [Mapping(Source = nameof(UserDao.FirstName), Target = nameof(UserInfo.Name))]
    UserInfo MapToDomainMoodel(UserDao userDao);       
}

The ClassName property in MappeAttribute is responsible for name of the generated mapping class. For default MappeAttribute interface prefix I is truncated or Impl added to the class name if there is no I prefix in the mapping interface or abstract class name.

Interface mapping

Use interfaces to prepare basic mapping. In a case when mapped object contains another objects, e.g.:

public class NoteDto
{
    public long Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public NoteDocumentDto Document { get; set; }
}

and

public class NoteDao
{
    public long Id { get; set; }
    public string PageTitle { get; set; }
    public string Description { get; set; }
    public DateTime ValidFrom { get; set; }
    public DateTime ValidTo { get; set; }
    public string CreatedBy { get; set; }
    public DateTime Created { get; set; }
    public DateTime Modified { get; set; }
    public NoteDocumentDao Document { get; set; }
}

it is enough to add mapping method to the interface for these types and the code generation processor will match and generate mappings for NoteDto MapToDto(NoteDao source) method:

[Mapper]
public interface INotesMapper
{
    [Mapping(Source = nameof(NoteDao.PageTitle), Target = nameof(NoteDto.Title))]
    NoteDto MapToDto(NoteDao source);

    [Mapping(Source = nameof(NoteDocumentDao.Metadata.CreatorFirstName), Target = nameof(NoteDocumentDto.Autor))]
    NoteDocumentDto MapToDto(NoteDocumentDao source);
}

the output will be:

public class NotesMapper : INotesMapper
{
    public static NotesMapper Create() => new();
    public virtual Compentio.Example.App.Entities.NoteDto MapToDto(Compentio.Example.App.Entities.NoteDao source)
    {
        var target = new Compentio.Example.App.Entities.NoteDto();
        target.Id = source.Id;
        target.Title = source.PageTitle;
        target.Description = source.Description;
        target.Document = MapDocumentToDto(source.Document);
        return target;
    }

    public virtual Compentio.Example.App.Entities.NoteDocumentDto MapDocumentToDto(Compentio.Example.App.Entities.NoteDocumentDao source)
    {
        var target = new Compentio.Example.App.Entities.NoteDocumentDto();
        target.Id = source.Id;
        target.Title = source.Title;
        return target;
    }
}

All methds are marked as virtual, so there is a possibility to override them in own mappers code.

Class mapping

For more complicated mapings use abstract class to define mappers. The main difference between abstract class mapper and interface, that Expression property can be used in MappingAttribute:

[Mapper(ClassName = "NotesMappings")]
public abstract class NotesClassMapper
{
    [Mapping(Target = nameof(NoteDocumentDto.Autor), Expression = nameof(ConvertAuthor))]
    public abstract NoteDocumentDto MapToDto(NoteDocumentDao source);

    protected readonly Func<NoteDocumentDao, string> ConvertAuthor = s => s.Metadata.CreatorFirstName + s.Metadata.CreatorLastName;
}

Expression - it is a name of mapping function, that can be used for additional properties mapping.

It must be public or protected, since it is used in generated mapper class that implements abstract mapping class.

Mapping collections

Lets assume we need to map two entities:

public class UserDao
{
    public long UserId { get; set; }
    public AddressDao[] UserAddresses { get; set; }
}

to

public class UserInfo
{
    public int Id { get; set; }
    public Address[] Addresses { get; set; }
}

It can be achieved using abstract class mapper:

[Mapper(ClassName = "UserDataMapper")]
public abstract class UserMapper
{
    [Mapping(Source = nameof(UserDao.UserAddresses), Target = nameof(UserInfo.Addresses), Expression = nameof(ConvertAddresses))]
    [Mapping(Source = nameof(UserDao.UserId), Target = nameof(UserInfo.Id), Expression = nameof(ConvertUserId))]
    public abstract UserInfoWithArray MapToDomainModel(UserWithArrayDao userWithArrayDao);

    protected Address[] ConvertAddresses(AddressDao[] addresses)
    {
        return addresses.Select(a => MapAddress(a)).ToArray();
    }
    
    protected static int ConvertUserId(long id)
    {
        return Convert.ToInt32(id);
    }

    public abstract Address MapAddress(AddressDao addressDao);
}

Dependency injection

To simplify adding dependency injection for mappers MappersDependencyInjectionExtensions class is generated, that can be used (for now only for Microsoft.Extensions.DependencyInjection) by adding AddMappers() that adds all mappers defined in the project:

 Host.CreateDefaultBuilder(args)
                .ConfigureServices((_, services) =>
                    services
                    //.here you services
                    //
                    .AddMappers());

The Compentio.SourceMapper searches for 3 main dependency container packages (Microsoft.Extensions.DependencyInjection, Autofac.Extensions.DependencyInjection, and StructureMap.Microsoft.DependencyInjection) and generates extension code. If there no any container packages found, Dependency Injection extension class in not generated.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.0.4 365 12/23/2021
2.0.0.3 268 12/23/2021
2.0.0.2 251 12/22/2021
2.0.0.1 263 12/2/2021
1.0.14 270 11/16/2021
1.0.13 268 11/15/2021
1.0.12 290 11/9/2021
1.0.11 349 10/18/2021
1.0.10 306 10/8/2021
1.0.9 308 10/8/2021
1.0.8 328 10/8/2021
1.0.7 305 10/7/2021
1.0.6 310 10/7/2021
1.0.5-rc 216 10/1/2021
1.0.4-rc 203 9/30/2021
1.0.3-rc 190 9/29/2021
1.0.2-rc 200 9/29/2021
0.0.2-beta 204 9/28/2021