HaloMapper 0.2.0
dotnet add package HaloMapper --version 0.2.0
NuGet\Install-Package HaloMapper -Version 0.2.0
<PackageReference Include="HaloMapper" Version="0.2.0" />
<PackageVersion Include="HaloMapper" Version="0.2.0" />
<PackageReference Include="HaloMapper" />
paket add HaloMapper --version 0.2.0
#r "nuget: HaloMapper, 0.2.0"
#:package HaloMapper@0.2.0
#addin nuget:?package=HaloMapper&version=0.2.0
#tool nuget:?package=HaloMapper&version=0.2.0
HaloMapper π
A high-performance, AutoMapper-compatible object mapping library for .NET with advanced features like projection support, flattening, expression compilation, and comprehensive validation.
Why Choose HaloMapper? π€
Feature | HaloMapper | AutoMapper | Benefit |
---|---|---|---|
Performance | β‘ Expression Compilation | β Standard | 2-3x faster mapping |
Memory Usage | π Optimized | β Standard | Lower memory footprint |
API Compatibility | β 95% Compatible | β Native | Drop-in replacement |
Startup Validation | β Built-in | β Available | Same feature, better errors |
Projection | β Native | β Native | Equal functionality |
Type Converters | β Extensible | β Extensible | Same extensibility |
Bundle Size | π₯ Lightweight | β Standard | Smaller deployment |
Quick Start Guide π
1. Installation
# For basic mapping
dotnet add package HaloMapper
# For ASP.NET Core / Dependency Injection
dotnet add package HaloMapper.Extensions.DependencyInjection
2. Basic Usage
// Simple mapping
var config = new MapperConfiguration();
config.CreateMap<Person, PersonDto>();
var mapper = new Mapper(config);
var dto = mapper.Map<Person, PersonDto>(person);
3. ASP.NET Core Integration
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add HaloMapper to DI container
builder.Services.AddHaloMapper(Assembly.GetExecutingAssembly());
var app = builder.Build();
// Controller
[ApiController]
public class PersonController : ControllerBase
{
private readonly IMapper _mapper;
public PersonController(IMapper mapper) => _mapper = mapper;
[HttpGet("{id}")]
public async Task<PersonDto> GetPerson(int id)
{
var person = await _personService.GetByIdAsync(id);
return _mapper.Map<Person, PersonDto>(person);
}
}
Configuration Methods π οΈ
Profile-Based Configuration (Recommended)
public class MappingProfile : Profile
{
public override void Configure()
{
// Basic mapping
CreateMap<Person, PersonDto>();
// Advanced mapping with custom logic
CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, o => o.MapFrom(s => s.Customer.FirstName + " " + s.Customer.LastName))
.ForMember(d => d.Total, o => o.MapFrom(s => s.Items.Sum(i => i.Price * i.Quantity)))
.ForMember(d => d.ItemCount, o => o.MapFrom(s => s.Items.Count))
.ForMember(d => d.InternalNotes, o => o.Ignore())
.AfterMap((src, dest) => dest.MappedAt = DateTime.UtcNow);
// Conditional mapping
CreateMap<User, UserDto>()
.ForMember(d => d.Email, o => o.Condition(s => s.IsEmailPublic))
.ForMember(d => d.Phone, o => o.NullSubstitute("Not provided"));
// Flattening (automatic)
CreateMap<Employee, EmployeeDto>(); // Employee.Address.City β EmployeeDto.AddressCity
}
}
Direct Configuration
var config = new MapperConfiguration();
config.CreateMap<Person, PersonDto>()
.ForMember(d => d.FullName, o => o.MapFrom(s => $"{s.FirstName} {s.LastName}"))
.ConstructUsing(src => new PersonDto { CreatedAt = DateTime.UtcNow });
var mapper = new Mapper(config);
Dependency Injection Options π
Option 1: Assembly Scanning (Recommended)
// Scans current assembly for Profile classes
builder.Services.AddHaloMapper();
// Scans specific assemblies
builder.Services.AddHaloMapper(
Assembly.GetExecutingAssembly(),
Assembly.GetAssembly(typeof(BusinessLogicProfile))
);
Option 2: Marker Type
// Scans assembly containing MappingProfile
builder.Services.AddHaloMapper<MappingProfile>();
Option 3: Explicit Profile Types
// Register specific profiles
builder.Services.AddHaloMapper(
typeof(PersonProfile),
typeof(OrderProfile),
typeof(ProductProfile)
);
Option 4: Custom Configuration
builder.Services.AddHaloMapper(config =>
{
config.CreateMap<Person, PersonDto>();
config.CreateMap<Order, OrderDto>();
// Add custom type converter
config.AddTypeConverter<string, Guid>(new StringToGuidConverter());
});
Option 5: Scoped Mapper (Per-Request)
// For scenarios requiring per-request configuration
builder.Services.AddScopedHaloMapper(config =>
{
config.CreateMap<Person, PersonDto>();
// Configuration can vary per request
});
Advanced Features π₯
1. Projection Support (Entity Framework)
Perfect for reducing database queries and improving performance:
// Instead of this (loads full entities):
var orders = await context.Orders
.Include(o => o.Customer)
.Include(o => o.Items)
.ToListAsync();
var dtos = mapper.Map<List<Order>, List<OrderDto>>(orders);
// Do this (only selects needed fields):
var dtos = await context.Orders
.Where(o => o.Status == OrderStatus.Active)
.ProjectTo<OrderDto>(mapperConfig)
.ToListAsync();
// Works with complex projections
var summary = await context.Orders
.Where(o => o.CreatedAt >= DateTime.Today.AddDays(-30))
.ProjectTo<OrderSummaryDto>(mapperConfig)
.GroupBy(o => o.CustomerId)
.Select(g => new CustomerOrderSummary
{
CustomerId = g.Key,
OrderCount = g.Count(),
TotalAmount = g.Sum(o => o.Total)
})
.ToListAsync();
2. Automatic Flattening
HaloMapper automatically flattens nested properties:
public class Order
{
public int Id { get; set; }
public Customer Customer { get; set; }
public ShippingAddress ShippingAddress { get; set; }
}
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class ShippingAddress
{
public string Street { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
public class OrderDto
{
public int Id { get; set; }
public string CustomerFirstName { get; set; } // β Automatically mapped from Order.Customer.FirstName
public string CustomerLastName { get; set; } // β Automatically mapped from Order.Customer.LastName
public string CustomerEmail { get; set; } // β Automatically mapped from Order.Customer.Email
public string ShippingAddressStreet { get; set; } // β Automatically mapped from Order.ShippingAddress.Street
public string ShippingAddressCity { get; set; } // β Automatically mapped from Order.ShippingAddress.City
public string ShippingAddressPostalCode { get; set; } // β Automatically mapped from Order.ShippingAddress.PostalCode
}
// Configuration - flattening is automatic!
config.CreateMap<Order, OrderDto>();
3. Type Converters
Handle complex type transformations:
// Custom converter
public class MoneyToStringConverter : ITypeConverter<Money, string>
{
public string Convert(Money source) => $"{source.Amount:C} {source.Currency}";
}
// Registration and usage
config.AddTypeConverter(new MoneyToStringConverter());
config.CreateMap<Order, OrderDisplayDto>(); // Money properties automatically converted to strings
Built-in converters included for:
- Primitives (string β int, decimal, DateTime, etc.)
- Enums β strings
- Nullable types
- Collections
4. Configuration Validation
Catch mapping errors at startup, not runtime:
var config = new MapperConfiguration();
config.CreateMap<Person, PersonDto>();
config.CreateMap<Order, OrderDto>();
// Validate all mappings
var validation = config.ValidateConfiguration();
if (!validation.IsValid)
{
foreach (var error in validation.Errors)
Console.WriteLine($"ERROR: {error}");
foreach (var warning in validation.Warnings)
Console.WriteLine($"WARNING: {warning}");
}
// Or throw exception on invalid config (recommended for startup)
config.AssertConfigurationIsValid();
Sample validation output:
ERROR: Cannot map property 'ComplexProperty' of type ComplexType to property 'ComplexProperty' of type AnotherComplexType [Order -> OrderDto.ComplexProperty]
WARNING: Unmapped destination member 'FullName' [Person -> PersonDto.FullName]
WARNING: Source member 'InternalId' is not mapped to any destination member [Person -> PersonDto.InternalId]
5. Performance Optimization
var config = new MapperConfiguration
{
UseCompiledExpressions = true // Default: true (recommended)
};
// Compiled expressions provide 2-3x performance improvement
// over reflection-based mapping
6. Collection Mapping
// All collection types supported
List<PersonDto> dtoList = mapper.MapCollection<Person, PersonDto>(people).ToList();
PersonDto[] dtoArray = mapper.MapCollection<Person, PersonDto>(people).ToArray();
IEnumerable<PersonDto> dtoEnum = mapper.MapCollection<Person, PersonDto>(people);
// Works with all IEnumerable implementations
var hashSet = new HashSet<Person>(people);
var dtoCollection = mapper.MapCollection<Person, PersonDto>(hashSet);
Member Configuration Options ποΈ
Basic Member Mapping
config.CreateMap<Person, PersonDto>()
.ForMember(d => d.FullName, o => o.MapFrom(s => s.FirstName + " " + s.LastName))
.ForMember(d => d.Age, o => o.MapFrom(s => DateTime.Today.Year - s.BirthDate.Year))
.ForMember(d => d.SecretData, o => o.Ignore());
Conditional Mapping
config.CreateMap<User, UserDto>()
.ForMember(d => d.Email, o => o.Condition(s => s.IsEmailPublic))
.ForMember(d => d.Phone, o => o.Condition((src, dest) => src.IsActive && dest != null));
Null Handling
config.CreateMap<Person, PersonDto>()
.ForMember(d => d.MiddleName, o => o.NullSubstitute("N/A"))
.ForMember(d => d.Nickname, o => o.NullSubstitute(string.Empty));
Custom Value Resolvers
config.CreateMap<Order, OrderDto>()
.ForMember(d => d.StatusText, o => o.ResolveUsing((src, dest) =>
{
return src.Status switch
{
OrderStatus.Pending => "Awaiting Processing",
OrderStatus.Shipped => $"Shipped on {src.ShippedDate:MM/dd/yyyy}",
OrderStatus.Delivered => "Successfully Delivered",
_ => "Unknown Status"
};
}));
Object Construction
config.CreateMap<Person, PersonDto>()
.ConstructUsing(src => new PersonDto
{
Id = Guid.NewGuid(),
CreatedAt = DateTime.UtcNow,
CreatedBy = "System"
});
Lifecycle Hooks
config.CreateMap<Person, PersonDto>()
.BeforeMap((src, dest) => Console.WriteLine($"Starting mapping for {src.Name}"))
.AfterMap((src, dest) =>
{
dest.MappedAt = DateTime.UtcNow;
dest.Version = "1.0";
});
Migration from AutoMapper π
HaloMapper is designed as a drop-in replacement for AutoMapper. Here's your migration guide:
Step 1: Update Package References
<PackageReference Include="HaloMapper" Version="1.0.0" />
<PackageReference Include="HaloMapper.Extensions.DependencyInjection" Version="1.0.0" />
Step 2: Update Using Statements
// Change this:
using AutoMapper;
// To this:
using HaloMapper;
Step 3: Update Dependency Injection
// AutoMapper registration:
services.AddAutoMapper(typeof(MappingProfile));
// HaloMapper registration (choose one):
services.AddHaloMapper<MappingProfile>(); // Marker type
services.AddHaloMapper(Assembly.GetExecutingAssembly()); // Assembly scan
services.AddHaloMapper(typeof(MappingProfile)); // Explicit type
Step 4: Profile Migration
Most AutoMapper profiles work without changes:
// This AutoMapper profile:
public class PersonProfile : AutoMapper.Profile
{
public PersonProfile()
{
CreateMap<Person, PersonDto>()
.ForMember(d => d.FullName, o => o.MapFrom(s => s.FirstName + " " + s.LastName));
}
}
// Becomes this HaloMapper profile:
public class PersonProfile : HaloMapper.Profile
{
public override void Configure() // β Main difference: Configure() method
{
CreateMap<Person, PersonDto>()
.ForMember(d => d.FullName, o => o.MapFrom(s => s.FirstName + " " + s.LastName));
}
}
Step 5: Projection Migration
// AutoMapper projection:
var dtos = await context.Orders
.ProjectTo<OrderDto>(mapper.ConfigurationProvider)
.ToListAsync();
// HaloMapper projection:
var dtos = await context.Orders
.ProjectTo<OrderDto>(mapperConfiguration) // β Use MapperConfiguration instead
.ToListAsync();
API Compatibility Matrix
Feature | AutoMapper | HaloMapper | Notes |
---|---|---|---|
CreateMap<T1, T2>() |
β | β | Identical |
ForMember() |
β | β | Identical |
MapFrom() |
β | β | Identical |
Ignore() |
β | β | Identical |
Condition() |
β | β | Identical |
ConstructUsing() |
β | β | Identical |
BeforeMap() / AfterMap() |
β | β | Identical |
ProjectTo<T>() |
β | β | Parameter difference (see above) |
Profile base class | β | β | Constructor β Configure() method |
AssertConfigurationIsValid() |
β | β | Identical |
Known Differences
- Profile Definition: AutoMapper uses constructor, HaloMapper uses
Configure()
method - ProjectTo Parameter: AutoMapper uses
IConfigurationProvider
, HaloMapper usesMapperConfiguration
- Performance: HaloMapper uses expression compilation by default (faster)
Migration Checklist β
- Update package references
- Update using statements
- Update DI registration
- Change Profile constructors to
Configure()
methods - Update
ProjectTo
calls to useMapperConfiguration
- Test all mappings
- Run performance benchmarks (should be faster!)
- Update documentation
Real-World Examples π
E-Commerce Application
public class ECommerceMappingProfile : Profile
{
public override void Configure()
{
// Product mappings
CreateMap<Product, ProductDto>()
.ForMember(d => d.CategoryName, o => o.MapFrom(s => s.Category.Name))
.ForMember(d => d.IsOnSale, o => o.MapFrom(s => s.SalePrice.HasValue))
.ForMember(d => d.DisplayPrice, o => o.MapFrom(s => s.SalePrice ?? s.Price))
.ForMember(d => d.ImageUrls, o => o.MapFrom(s => s.Images.Select(i => i.Url)));
// Order mappings with complex calculations
CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, o => o.MapFrom(s => $"{s.Customer.FirstName} {s.Customer.LastName}"))
.ForMember(d => d.ItemCount, o => o.MapFrom(s => s.Items.Sum(i => i.Quantity)))
.ForMember(d => d.Subtotal, o => o.MapFrom(s => s.Items.Sum(i => i.Price * i.Quantity)))
.ForMember(d => d.Tax, o => o.MapFrom(s => s.Items.Sum(i => i.Price * i.Quantity * 0.08m)))
.ForMember(d => d.ShippingCost, o => o.MapFrom(s => s.ShippingMethod.Cost))
.ForMember(d => d.Total, o => o.MapFrom(s =>
s.Items.Sum(i => i.Price * i.Quantity) +
s.Items.Sum(i => i.Price * i.Quantity * 0.08m) +
s.ShippingMethod.Cost))
.AfterMap((src, dest) => dest.OrderNumber = $"ORD-{src.Id:D6}");
// Customer with privacy controls
CreateMap<Customer, CustomerDto>()
.ForMember(d => d.Email, o => o.Condition(s => s.IsEmailPublic))
.ForMember(d => d.Phone, o => o.Condition(s => s.IsPhonePublic))
.ForMember(d => d.DateOfBirth, o => o.Condition(s => s.IsAgePublic))
.ForMember(d => d.LastLoginDisplay, o => o.MapFrom(s =>
s.LastLogin.HasValue ? s.LastLogin.Value.ToString("MMM dd, yyyy") : "Never"));
}
}
API Response Mapping
public class ApiMappingProfile : Profile
{
public override void Configure()
{
// Entity to API response
CreateMap<User, UserResponse>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id.ToString()))
.ForMember(d => d.FullName, o => o.MapFrom(s => $"{s.FirstName} {s.LastName}"))
.ForMember(d => d.AvatarUrl, o => o.MapFrom(s => s.Avatar != null ? $"/avatars/{s.Avatar.FileName}" : "/avatars/default.png"))
.ForMember(d => d.MemberSince, o => o.MapFrom(s => s.CreatedAt.ToString("MMMM yyyy")))
.ForMember(d => d.IsOnline, o => o.MapFrom(s => s.LastActivity > DateTime.UtcNow.AddMinutes(-5)))
.AfterMap((src, dest) => dest.Links = new UserLinks
{
Self = $"/api/users/{src.Id}",
Posts = $"/api/users/{src.Id}/posts",
Followers = $"/api/users/{src.Id}/followers"
});
// API request to entity
CreateMap<CreateUserRequest, User>()
.ConstructUsing(src => new User
{
Id = Guid.NewGuid(),
CreatedAt = DateTime.UtcNow,
IsActive = true
})
.ForMember(d => d.Email, o => o.MapFrom(s => s.Email.ToLowerInvariant()))
.ForMember(d => d.UserName, o => o.MapFrom(s => s.UserName.ToLowerInvariant()));
}
}
Database Query Optimization with Projection
// Controller method
[HttpGet]
public async Task<IActionResult> GetProducts(int page = 1, int pageSize = 20)
{
// This generates optimal SQL - only selects needed columns
var products = await _context.Products
.Include(p => p.Category)
.Include(p => p.Images)
.Where(p => p.IsActive)
.OrderBy(p => p.Name)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ProjectTo<ProductDto>(_mapperConfig)
.ToListAsync();
return Ok(products);
}
// Generated SQL only includes:
// SELECT p.Id, p.Name, p.Price, p.SalePrice, c.Name as CategoryName,
// (SELECT STRING_AGG(i.Url, ',') FROM Images i WHERE i.ProductId = p.Id) as ImageUrls
// FROM Products p
// JOIN Categories c ON p.CategoryId = c.Id
// WHERE p.IsActive = 1
// ORDER BY p.Name
// OFFSET @page ROWS FETCH NEXT @pageSize ROWS ONLY
Performance & Best Practices πββοΈ
Performance Tips
Use Compiled Expressions (enabled by default)
var config = new MapperConfiguration { UseCompiledExpressions = true // Default: true };
Use Projection for Database Queries
// β Bad - loads full entities then maps var orders = await context.Orders.ToListAsync(); var dtos = mapper.MapCollection<Order, OrderDto>(orders); // β Good - only selects needed columns var dtos = await context.Orders.ProjectTo<OrderDto>(config).ToListAsync();
Validate Configuration at Startup
// In Program.cs var app = builder.Build(); var mapperConfig = app.Services.GetRequiredService<MapperConfiguration>(); mapperConfig.AssertConfigurationIsValid(); // Fails fast if misconfigured
Memory Usage Tips
Reuse Mapper Instances (automatic with DI)
// β Good - registered as singleton services.AddHaloMapper<MappingProfile>(); // β Bad - creates new instance each time var mapper = new Mapper(new MapperConfiguration());
Avoid Complex Calculations in MapFrom
// β Bad - complex calculation on each mapping .ForMember(d => d.ComplexValue, o => o.MapFrom(s => ExpensiveCalculation(s))) // β Good - calculate once, store in source .ForMember(d => d.ComplexValue, o => o.MapFrom(s => s.PreCalculatedValue))
Best Practices
Organize Profiles by Domain
public class UserMappingProfile : Profile { /* User-related mappings */ } public class OrderMappingProfile : Profile { /* Order-related mappings */ } public class ProductMappingProfile : Profile { /* Product-related mappings */ }
Use Meaningful Names
// β Good .ForMember(d => d.CustomerFullName, o => o.MapFrom(s => $"{s.Customer.FirstName} {s.Customer.LastName}")) // β Bad .ForMember(d => d.Name, o => o.MapFrom(s => s.Something))
Handle Null Values Explicitly
.ForMember(d => d.MiddleName, o => o.NullSubstitute("N/A")) .ForMember(d => d.OptionalField, o => o.Condition(s => s.SomeProperty != null))
Document Complex Mappings
CreateMap<Order, OrderDto>() // Calculate total including tax and shipping .ForMember(d => d.Total, o => o.MapFrom(s => s.Items.Sum(i => i.Price * i.Quantity) + // Subtotal s.Items.Sum(i => i.Price * i.Quantity * 0.08m) + // Tax (8%) s.ShippingMethod.Cost)) // Shipping .AfterMap((src, dest) => { // Generate display-friendly order number dest.OrderNumber = $"ORD-{src.Id:D6}"; });
Troubleshooting π§
Common Issues and Solutions
1. "No mapping configuration found"
Problem: InvalidOperationException: No mapping configuration found for Person -> PersonDto
Solution: Ensure you've created the mapping configuration
config.CreateMap<Person, PersonDto>();
2. Validation Errors at Startup
Problem: InvalidOperationException: Configuration validation failed
Solution: Check validation details
var validation = config.ValidateConfiguration();
Console.WriteLine(validation.ToString()); // Shows specific errors
3. ProjectTo Not Working with EF Core
Problem: ProjectTo<T>()
method not found
Solution: Add using statement
using HaloMapper.Extensions;
4. Profile Not Being Discovered
Problem: Profiles not found during assembly scanning
Solution: Ensure profile has parameterless constructor and proper inheritance
public class MyProfile : Profile // β
Inherits from Profile
{
public override void Configure() // β
Overrides Configure method
{
CreateMap<Source, Dest>();
}
}
5. Performance Issues
Problem: Mapping is slower than expected
Solutions:
- Ensure
UseCompiledExpressions = true
(default) - Use projection instead of mapping full entities
- Avoid complex calculations in
MapFrom
6. Circular Reference Issues
Problem: StackOverflowException
during mapping
Solution: Configure maximum depth or break circular references
// Option 1: Break the circular reference
CreateMap<Parent, ParentDto>()
.ForMember(d => d.Children, o => o.MapFrom(s => s.Children.Select(c => new ChildDto { Name = c.Name })));
// Option 2: Use ignore for circular properties
CreateMap<Child, ChildDto>()
.ForMember(d => d.Parent, o => o.Ignore());
Advanced Topics π
Custom Type Converters
public class JsonToObjectConverter<T> : ITypeConverter<string, T>
{
public T Convert(string source)
{
if (string.IsNullOrEmpty(source))
return default(T);
return JsonSerializer.Deserialize<T>(source);
}
}
// Registration
config.AddTypeConverter(new JsonToObjectConverter<MyObject>());
Conditional Mapping with Complex Logic
config.CreateMap<User, UserDto>()
.ForMember(d => d.Permissions, o => o.MapFrom(s => GetUserPermissions(s)))
.ForMember(d => d.DisplayName, o => o.ResolveUsing((src, dest) =>
{
if (!string.IsNullOrEmpty(src.PreferredName))
return src.PreferredName;
if (!string.IsNullOrEmpty(src.FirstName) && !string.IsNullOrEmpty(src.LastName))
return $"{src.FirstName} {src.LastName}";
return src.UserName ?? "Unknown User";
}));
private static List<string> GetUserPermissions(User user)
{
var permissions = new List<string>();
if (user.IsAdmin) permissions.Add("admin");
if (user.CanModerate) permissions.Add("moderate");
if (user.CanPost) permissions.Add("post");
return permissions;
}
Contributing π€
We welcome contributions! Here's how to get started:
- Fork the repository
- Clone your fork:
git clone https://github.com/<your-username>/halomapper.git
- Create a new branch:
git checkout -b feature/my-new-feature
- Make your changes and add tests
- Commit your changes:
git commit -m "Describe your changes"
- Push to your fork:
git push origin feature/my-new-feature
- Open a Pull Request on GitHub
Development Setup
# Clone the repository
git clone https://github.com/0101coding/halomapper.git
cd halomapper
# Restore dependencies
dotnet restore
# Run tests
dotnet test
# Build
dotnet build
Support π¬
- π Bug Reports: GitHub Issues
Roadmap πΊοΈ
- v1.1: Async mapping support
- v1.2: Custom naming conventions
- v1.3: Source generators for compile-time mapping
- v2.0: Multi-threading optimizations
- v2.1: Memory mapping for ultra-large objects
License π
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ by the HaloMapper team
HaloMapper - High-performance object mapping for .NET π
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
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on HaloMapper:
Package | Downloads |
---|---|
HaloMapper.Extensions.DependencyInjection
Dependency injection extensions for HaloMapper, providing seamless integration with Microsoft.Extensions.DependencyInjection. Includes profile auto-discovery, assembly scanning, and configuration validation. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
0.2.0 | 25 | 9/17/2025 |
0.1.0 | 127 | 9/10/2025 |
0.1.0-ci.2 | 113 | 9/10/2025 |
v1.0.0 - Initial release with core mapping features:
- High-performance expression compilation
- AutoMapper-compatible API
- Projection support for Entity Framework
- Automatic flattening and unflattening
- Comprehensive configuration validation
- Type converter system
- Profile-based configuration