Myth.Morph 3.0.3

dotnet add package Myth.Morph --version 3.0.3
                    
NuGet\Install-Package Myth.Morph -Version 3.0.3
                    
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="Myth.Morph" Version="3.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Myth.Morph" Version="3.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Myth.Morph" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Myth.Morph --version 3.0.3
                    
#r "nuget: Myth.Morph, 3.0.3"
                    
#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.
#:package Myth.Morph@3.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Myth.Morph&version=3.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Myth.Morph&version=3.0.3
                    
Install as a Cake Tool

Myth.Morph

NuGet Version NuGet Version

License

pt-br en

A powerful .NET library for object transformation and mapping. Myth.Morph provides a flexible and extensible system for converting between different types with support for both convention-based and custom mappings.

The main goal is to simplify object mapping scenarios while providing high flexibility and performance through dependency injection integration and schema-based configuration.

⭐ Features

  • Simple and Intuitive: Easy-to-use extension methods for object transformation
  • Flexible Mapping: Support for automatic, custom, and instance-based mappings
  • Dependency Injection Integration: Full integration with Microsoft.Extensions.DependencyInjection
  • Generic Type Support: Automatic mapping for generic collections and interfaces
  • Asynchronous Operations: Built-in support for async property binding
  • Logging Integration: Comprehensive logging through Microsoft.Extensions.Logging
  • Exception Safety: Detailed exception handling with custom exception types
  • Schema-Based Configuration: Fluent API for configuring complex mappings

🕶️ Using

🚀 Quick Start

Installation and Setup

First, register Myth.Morph in your dependency injection container:

services.AddMorph();

Basic Usage

Transform objects using the extension methods:

// Simple transformation
var destination = source.To<DestinationType>();

// Transform with custom service provider
var destination = source.To<DestinationType>(serviceProvider);

// Transform collections
var destinationList = sourceList.To<DestinationType>();

// Async transformation
var destination = await source.ToAsync<DestinationType>();

Check if Mapping Exists

// Check if a mapping exists
bool canMap = source.CanBindTo<DestinationType>();

// Type-safe checking
bool canMap = source.CanBindTo<SourceType, DestinationType>();

📋 Instance-Based Mapping

Create custom mappings by implementing the IMorphable<TDestination> interface:

public class UserDto : IMorphable<User>
{
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime BirthDate { get; set; }
    
    public void MorphTo(Schema<User> schema)
    {
        schema
            .Bind(u => u.FullName, () => Name)
            .Bind(u => u.EmailAddress, () => Email)
            .Bind(u => u.Age, sp => CalculateAge(BirthDate))
            .BindAsync(u => u.Profile, async sp => 
            {
                var profileService = sp.GetService<IProfileService>();
                return await profileService.GetProfileAsync(Email);
            })
            .Ignore(u => u.InternalId);
    }
    
    private int CalculateAge(DateTime birthDate) 
        => DateTime.Today.Year - birthDate.Year;
}

⚙️ Advanced Schema Configuration

Synchronous Bindings

public void MorphTo(Schema<Destination> schema)
{
    // Bind with service provider resolver
    schema.Bind(d => d.Property, sp => 
    {
        var service = sp.GetService<IMyService>();
        return service.GetValue();
    });
    
    // Bind with direct resolver
    schema.Bind(d => d.Property, () => "Direct Value");
    
    // Ignore properties
    schema.Ignore(d => d.UnwantedProperty);
}

Asynchronous Bindings

public void MorphTo(Schema<Destination> schema)
{
    // Async binding with service provider
    schema.BindAsync(d => d.AsyncProperty, async sp =>
    {
        var service = sp.GetService<IAsyncService>();
        return await service.GetDataAsync();
    });
    
    // Async binding with direct resolver
    schema.BindAsync(d => d.AsyncProperty, async () =>
    {
        await Task.Delay(100);
        return "Async Value";
    });
}

🔧 Configuration Options

Assembly Configuration

services.AddMorph(settings =>
{
    // Add specific assemblies
    settings.AddAssembly(Assembly.GetExecutingAssembly());
    settings.AddAssemblies(assembly1, assembly2);
    
    // Clear and add custom assemblies
    settings.ClearAssemblies()
            .AddAssembly(customAssembly);
});

Generic Type Mappings

services.AddMorph(settings =>
{
    // Add custom interface to concrete mappings
    settings.AddGenericMorph(typeof(IMyInterface<>), typeof(MyImplementation<>));
    
    // Type-safe generic mapping
    settings.AddGenericMapping<ICustomCollection<>, CustomCollection<>>();
    
    // Clear default mappings and add custom ones
    settings.ClearGenericMappings()
            .AddGenericMapping<IList<>, ArrayList>();
});

Default Generic Mappings

The library includes these default mappings:

  • IList<>List<>
  • ICollection<>List<>
  • IDictionary<,>Dictionary<,>
  • ISet<>HashSet<>
  • IReadOnlyCollection<>ReadOnlyCollection<>
  • IReadOnlyList<>List<>
  • IReadOnlySet<>HashSet<>

🏗️ Complex Mapping Examples

Repository Pattern Integration

public class UserService
{
    private readonly IServiceProvider _serviceProvider;
    
    public UserService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    
    public async Task<UserDto> GetUserAsync(int userId)
    {
        var user = await GetUserFromDatabase(userId);
        return user.To<UserDto>(_serviceProvider);
    }
    
    public async Task<IEnumerable<UserDto>> GetUsersAsync()
    {
        var users = await GetUsersFromDatabase();
        return await users.ToAsync<UserDto>(_serviceProvider);
    }
}

Complex Object Transformation

public class OrderDto : IMorphable<Order>
{
    public int Id { get; set; }
    public string CustomerName { get; set; }
    public List<OrderItemDto> Items { get; set; }
    public decimal TotalAmount { get; set; }
    
    public void MorphTo(Schema<Order> schema)
    {
        schema
            .Bind(o => o.OrderId, () => Id)
            .Bind(o => o.Customer, sp =>
            {
                var customerService = sp.GetService<ICustomerService>();
                return customerService.GetCustomerByName(CustomerName);
            })
            .BindAsync(o => o.OrderItems, async sp =>
            {
                // Transform collection asynchronously
                return await Items.ToAsync<OrderItem>(sp);
            })
            .Bind(o => o.Total, () => TotalAmount)
            .BindAsync(o => o.ShippingInfo, async sp =>
            {
                var shippingService = sp.GetService<IShippingService>();
                return await shippingService.CalculateShippingAsync(Id);
            })
            .Ignore(o => o.InternalNotes);
    }
}

🎯 Use Cases

API Response Transformation

// Transform API responses to domain models
public async Task<User> GetUserFromApi(int userId)
{
    var apiResponse = await httpClient.GetAsync($"users/{userId}");
    var userDto = await apiResponse.Content.ReadFromJsonAsync<UserApiDto>();
    
    return userDto.To<User>();
}

Database Entity Mapping

// Transform database entities to DTOs
public async Task<IEnumerable<ProductDto>> GetProductsAsync()
{
    var entities = await dbContext.Products.ToListAsync();
    return entities.To<ProductDto>();
}

Event Sourcing Integration

public class UserCreatedEvent : IMorphable<User>
{
    public string UserId { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime CreatedAt { get; set; }
    
    public void MorphTo(Schema<User> schema)
    {
        schema
            .Bind(u => u.Id, () => UserId)
            .Bind(u => u.FullName, () => Name)
            .Bind(u => u.EmailAddress, () => Email)
            .Bind(u => u.CreatedDate, () => CreatedAt)
            .Bind(u => u.IsActive, () => true);
    }
}

🚨 Exception Handling

The library provides detailed exception handling:

Exception Types

  • BinderNotFoundException: Thrown when no mapping exists between source and destination types
  • BindException: Thrown when property or field binding operations fail
  • InvalidMorphConfigurationException: Thrown when the Morph system is not properly configured

Example Exception Handling

try
{
    var result = source.To<DestinationType>();
}
catch (BinderNotFoundException ex)
{
    // Handle missing mapping
    logger.LogError($"No mapping found: {ex.Message}");
}
catch (BindException ex)
{
    // Handle binding error
    logger.LogError($"Binding failed: {ex.Message}");
}
catch (InvalidMorphConfigurationException ex)
{
    // Handle configuration error
    logger.LogError($"Configuration issue: {ex.Message}");
}

📊 Performance Tips

  1. Reuse Service Provider: Pass the same service provider instance when transforming multiple objects
  2. Collection Transformation: Use type-specific collection methods for better performance
  3. Assembly Scanning: Limit assemblies in configuration to reduce startup time
  4. Async Operations: Use async methods for I/O-bound operations in bindings

🛠️ Troubleshooting

Common Issues

"ServiceProvider not configured" Error

// Ensure AddMorph() is called in DI configuration
services.AddMorph();

"No mapping found" Error

// Check if the source type implements IMorphable<TDestination>
public class MySource : IMorphable<MyDestination>
{
    public void MorphTo(Schema<MyDestination> schema) { /* implementation */ }
}

Generic Collection Mapping Issues

// Register appropriate generic mappings
services.AddMorph(settings =>
{
    settings.AddGenericMapping<IMyCollection<>, MyCollection<>>();
});

📝 Contributing

We welcome contributions! Please read our contributing guidelines and feel free to submit pull requests.

📄 License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows 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
3.0.3 168 8/30/2025
3.0.2 74 8/23/2025
3.0.2-preview.4 113 8/21/2025
3.0.2-preview.3 96 8/16/2025