Myth.Morph
3.0.4-preview.18
See the version list below for details.
dotnet add package Myth.Morph --version 3.0.4-preview.18
NuGet\Install-Package Myth.Morph -Version 3.0.4-preview.18
<PackageReference Include="Myth.Morph" Version="3.0.4-preview.18" />
<PackageVersion Include="Myth.Morph" Version="3.0.4-preview.18" />
<PackageReference Include="Myth.Morph" />
paket add Myth.Morph --version 3.0.4-preview.18
#r "nuget: Myth.Morph, 3.0.4-preview.18"
#:package Myth.Morph@3.0.4-preview.18
#addin nuget:?package=Myth.Morph&version=3.0.4-preview.18&prerelease
#tool nuget:?package=Myth.Morph&version=3.0.4-preview.18&prerelease
Myth.Morph
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 typesBindException: Thrown when property or field binding operations failInvalidMorphConfigurationException: 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
- Reuse Service Provider: Pass the same service provider instance when transforming multiple objects
- Collection Transformation: Use type-specific collection methods for better performance
- Assembly Scanning: Limit assemblies in configuration to reduce startup time
- 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 | Versions 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. |
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Myth.Commons (>= 3.0.4-preview.18)
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 |
|---|---|---|
| 4.2.1-preview.1 | 32 | 12/2/2025 |
| 4.2.0 | 87 | 11/30/2025 |
| 4.2.0-preview.1 | 44 | 11/29/2025 |
| 4.1.0 | 162 | 11/27/2025 |
| 4.1.0-preview.3 | 124 | 11/27/2025 |
| 4.1.0-preview.2 | 122 | 11/27/2025 |
| 4.1.0-preview.1 | 122 | 11/26/2025 |
| 4.0.1 | 149 | 11/22/2025 |
| 4.0.1-preview.8 | 141 | 11/22/2025 |
| 4.0.1-preview.7 | 150 | 11/22/2025 |
| 4.0.1-preview.6 | 135 | 11/22/2025 |
| 4.0.1-preview.5 | 195 | 11/21/2025 |
| 4.0.1-preview.4 | 201 | 11/21/2025 |
| 4.0.1-preview.3 | 208 | 11/21/2025 |
| 4.0.1-preview.2 | 228 | 11/21/2025 |
| 4.0.1-preview.1 | 245 | 11/21/2025 |
| 4.0.0 | 383 | 11/20/2025 |
| 4.0.0-preview.3 | 337 | 11/19/2025 |
| 4.0.0-preview.2 | 84 | 11/15/2025 |
| 4.0.0-preview.1 | 104 | 11/15/2025 |
| 3.10.0 | 162 | 11/15/2025 |
| 3.0.5-preview.15 | 145 | 11/14/2025 |
| 3.0.5-preview.14 | 214 | 11/12/2025 |
| 3.0.5-preview.13 | 226 | 11/12/2025 |
| 3.0.5-preview.12 | 218 | 11/11/2025 |
| 3.0.5-preview.11 | 220 | 11/11/2025 |
| 3.0.5-preview.10 | 219 | 11/11/2025 |
| 3.0.5-preview.9 | 211 | 11/10/2025 |
| 3.0.5-preview.8 | 82 | 11/8/2025 |
| 3.0.5-preview.7 | 89 | 11/8/2025 |
| 3.0.5-preview.6 | 85 | 11/8/2025 |
| 3.0.5-preview.5 | 86 | 11/8/2025 |
| 3.0.5-preview.4 | 59 | 11/7/2025 |
| 3.0.5-preview.3 | 135 | 11/4/2025 |
| 3.0.5-preview.2 | 137 | 11/4/2025 |
| 3.0.5-preview.1 | 131 | 11/4/2025 |
| 3.0.4 | 181 | 11/3/2025 |
| 3.0.4-preview.19 | 69 | 11/2/2025 |
| 3.0.4-preview.18 | 72 | 11/1/2025 |
| 3.0.4-preview.17 | 72 | 11/1/2025 |
| 3.0.4-preview.16 | 71 | 11/1/2025 |
| 3.0.4-preview.15 | 66 | 10/31/2025 |
| 3.0.4-preview.14 | 130 | 10/31/2025 |
| 3.0.4-preview.13 | 137 | 10/30/2025 |
| 3.0.4-preview.12 | 123 | 10/23/2025 |
| 3.0.4-preview.11 | 121 | 10/23/2025 |
| 3.0.4-preview.10 | 121 | 10/23/2025 |
| 3.0.4-preview.9 | 120 | 10/23/2025 |
| 3.0.4-preview.8 | 117 | 10/22/2025 |
| 3.0.4-preview.6 | 115 | 10/21/2025 |
| 3.0.4-preview.5 | 117 | 10/21/2025 |
| 3.0.4-preview.4 | 119 | 10/20/2025 |
| 3.0.4-preview.3 | 125 | 10/20/2025 |
| 3.0.4-preview.2 | 45 | 10/18/2025 |
| 3.0.4-preview.1 | 121 | 10/7/2025 |
| 3.0.3 | 197 | 8/30/2025 |
| 3.0.2 | 101 | 8/23/2025 |
| 3.0.2-preview.4 | 123 | 8/21/2025 |
| 3.0.2-preview.3 | 106 | 8/16/2025 |