DynaBee 1.4.0
dotnet add package DynaBee --version 1.4.0
NuGet\Install-Package DynaBee -Version 1.4.0
<PackageReference Include="DynaBee" Version="1.4.0" />
<PackageVersion Include="DynaBee" Version="1.4.0" />
<PackageReference Include="DynaBee" />
paket add DynaBee --version 1.4.0
#r "nuget: DynaBee, 1.4.0"
#:package DynaBee@1.4.0
#addin nuget:?package=DynaBee&version=1.4.0
#tool nuget:?package=DynaBee&version=1.4.0
DynaBee
DynaBee is a lightweight .NET library that uses Reflection.Emit to generate dynamic types at runtime.
It is designed for scenarios where you need to build classes, methods, properties, and contracts programmatically, with a fluent API that is simple to use and easy to extend.
The recommended application model is DI-first: define DynaBeeProfile classes, let DynaBee discover them, and resolve generated assembly contexts through IDynaBeeAssemblyCatalog.
What It Solves
- Runtime type generation without producing intermediate source code.
- Fluent creation of classes, interfaces, structs, enums, and records.
- Method implementation through IL, lambdas, expression trees, or high-level method body builders.
- Dependency injection integration.
- DI-first generation plans that consumer libraries can inspect before emission.
- Base constructor forwarding and virtual/abstract method or property overrides without consumer-side emit plumbing.
- Selective DI registration as concrete types, interfaces, or arbitrary assignable service/base types.
- Typed metadata for external extensions (for example EF or other frameworks).
- Assembly cache/versioning to reduce type build overhead.
Requirements
- .NET SDK 10.0+ recommended for development.
- The library multi-targets:
net8.0,net9.0, andnet10.0.
Installation
dotnet add package DynaBee
For test projects that validate generated assemblies:
dotnet add package DynaBee.Testing
Getting Started
1) Define a profile
using DynaBee.FluentApi;
using DynaBee.FluentApi.DependencyInjection;
using System.Linq.Expressions;
public sealed class SalesProfile : DynaBeeProfile
{
public SalesProfile() : base("Demo.Sales")
{
}
public override void Configure(IBeeAssemblyBuilder builder)
{
builder
.AddClass("Calculator", c => c
.Implements<ICalculator>(registerInDi: true)
.RegisterAsConcrete(false)
.AddMethod(nameof(ICalculator.Sum), typeof(int), m => m
.WithParameter<int>("x")
.WithParameter<int>("y")
.EmitsExpression((Expression<Func<int, int, int>>)((x, y) => x + y))))
.AddClass("InvoiceService", c => c
.Implements<IInvoiceService>(registerInDi: true)
.Implements<IInternalContract>(registerInDi: false)
.RegisterAsConcrete(false)
.Inject<IUnitOfWork>("UnitOfWork")
.AddMethod(nameof(IInvoiceService.Commit), typeof(int), m => m
.EmitsInjectedLambda<IUnitOfWork, int>("UnitOfWork", uow => uow.SaveChanges())));
}
}
public interface ICalculator
{
int Sum(int x, int y);
}
public interface IInvoiceService
{
int Commit();
}
public interface IInternalContract
{
string Hidden();
}
public interface IUnitOfWork
{
int SaveChanges();
}
2) Register DynaBee through DI
Profiles are the recommended way to organize dynamic types in larger applications. Each profile belongs to exactly one logical dynamic assembly. DynaBee discovers profiles, groups them by assembly name, builds each assembly context, and registers generated types in DI.
using DynaBee.FluentApi.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddSingleton<IUnitOfWork>(new UnitOfWork());
services.AddDynaBeeProfiles(
ServiceLifetime.Transient,
typeof(SalesProfile).Assembly);
var provider = services.BuildServiceProvider();
var catalog = provider.GetRequiredService<IDynaBeeAssemblyCatalog>();
var salesContext = catalog.GetContext("Demo.Sales");
var calculator = provider.GetRequiredService<ICalculator>();
var invoiceService = provider.GetRequiredService<IInvoiceService>();
var total = calculator.Sum(5, 3); // 8
var rows = invoiceService.Commit(); // Calls IUnitOfWork.SaveChanges()
public sealed class UnitOfWork : IUnitOfWork
{
public int SaveChanges() => 42;
}
3) Explicit registry setup
If you prefer explicit setup, AddDynaBeeRegistry(...) creates a single
mutable registry/provider pair for one logical dynamic assembly and registers
the initial generated types automatically.
using DynaBee.FluentApi.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System.Linq.Expressions;
var services = new ServiceCollection();
services.AddDynaBeeRegistry("Demo.Runtime", registry =>
{
registry.Configure(builder => builder
.AddClass("Greeter", c => c
.AddMethod("SayHello", typeof(string), m => m
.WithParameter<string>("name")
.EmitsExpression((Expression<Func<string, string>>)(name => "Hello " + name)))));
});
var provider = services.BuildServiceProvider();
var context = provider.GetRequiredService<IAssemblyContext>();
4) Descriptor-driven generation plans
Consumer libraries can normalize their own descriptors into a DynaBee generation
plan, inspect that plan before emission, and then apply it to any
IBeeAssemblyBuilder supplied by the DI-first registry/factory pipeline.
Plans are generic: they describe runtime types, inheritance, implemented interfaces, constructors, members, DI registration metadata, and descriptor correlation metadata. They do not impose application-level semantics.
using DynaBee.FluentApi;
using DynaBee.FluentApi.DependencyInjection;
using DynaBee.FluentApi.Generation;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
var executeMethod = typeof(RuntimeHandlerBase)
.GetMethod(nameof(RuntimeHandlerBase.Execute))!;
var baseConstructor = typeof(RuntimeHandlerBase)
.GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
binder: null,
new[] { typeof(IServiceProvider) },
modifiers: null)!;
var plan = new DynaBeeGenerationPlan("Demo.Handlers")
.WithMetadata("descriptor.batch", "handlers-v1")
.AddClass("GeneratedHandler", type => type
.Inherits(typeof(RuntimeHandlerBase))
.RegisterAs(typeof(RuntimeHandlerBase))
.RegisterAsConcrete(false)
.WithMetadata("descriptor.key", "handler:orders")
.AddConstructor(ctor => ctor
.WithParameter<IServiceProvider>("serviceProvider")
.CallsBase(baseConstructor, args => args.Argument("serviceProvider")))
.OverrideMethod(executeMethod, method => method
.EmitsBody(body => body.Return(body.Constant("Handled")))));
// The plan can be inspected before any dynamic type is emitted.
var plannedClass = plan.Classes[0];
Console.WriteLine(plannedClass.BaseType);
Console.WriteLine(plannedClass.Metadata["descriptor.key"]);
var services = new ServiceCollection();
services.AddSingleton<NameFormatter>();
services.AddDynaBeeRegistry(plan.AssemblyName, registry =>
{
registry.Configure(builder => plan.ApplyTo(builder));
});
var provider = services.BuildServiceProvider();
var handler = provider.GetRequiredService<RuntimeHandlerBase>();
var result = handler.Execute("orders"); // "Handled"
public abstract class RuntimeHandlerBase
{
protected RuntimeHandlerBase(IServiceProvider serviceProvider)
{
Formatter = serviceProvider.GetRequiredService<NameFormatter>();
}
protected NameFormatter Formatter { get; }
public abstract string Execute(string input);
}
public sealed class NameFormatter
{
public string Format(string value) => $"Formatted: {value}";
}
Generated classes can also override virtual or abstract properties:
var nameProperty = typeof(RuntimeQueryBase)
.GetProperty(nameof(RuntimeQueryBase.Name))!;
registry.Configure(builder => builder
.AddClass("GeneratedQuery", type => type
.Inherits(typeof(RuntimeQueryBase))
.OverrideProperty(nameProperty, property => property
.WithMetadata("descriptor.member", "query:name")
.Getter(get => get.ReturnsConstant("Orders")))));
public abstract class RuntimeQueryBase
{
public virtual string Name => "Base";
}
5) Method body builder for mapper generation
EmitsBody(...) lets integrations build complete method bodies without using
IL opcodes. It supports parameters, locals, object construction, instance/static
property and field access, constants, default values, nullable checks, enum and
numeric conversions, assignments, conditionals, method calls, access to the
generated instance through Self(), side-effect evaluation, and returns.
using DynaBee.FluentApi;
using DynaBee.FluentApi.DependencyInjection;
using System.Linq.Expressions;
public sealed class MappingProfile : DynaBeeProfile
{
public MappingProfile() : base("Demo.Mapping")
{
}
public override void Configure(IBeeAssemblyBuilder builder)
{
builder.AddClass("UserMapper", c => c
.AddMethod("Map", typeof(UserDto), m => m
.WithParameter<User>("source")
.EmitsBody(body =>
{
var source = body.Parameter<User>("source");
var destination = body.DeclareLocal<UserDto>("destination");
body.Assign(destination, body.New<UserDto>());
body.Assign(
body.Property(destination, nameof(UserDto.DisplayName)),
body.Concat(
body.Property(source, nameof(User.FirstName)),
body.Constant(" "),
body.Property(source, nameof(User.LastName))));
body.Assign(
body.Property(destination, nameof(UserDto.Total)),
body.Convert<decimal>(body.Property(source, nameof(User.Total))));
body.Assign(
body.Property(destination, nameof(UserDto.Name)),
body.If(
body.IsNull(body.Property(source, nameof(User.Name))),
body.Constant("Unknown"),
body.Property(source, nameof(User.Name))));
body.Return(destination);
}));
}
}
6) DI-based resolver method bodies
DynaBee does not own service lifetimes. Instead, generated method bodies can call whatever service provider or resolver API your integration chooses. This keeps framework-specific concerns outside the core library while still avoiding direct IL in integrations.
using DynaBee.FluentApi;
using DynaBee.FluentApi.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
public sealed class ResolverProfile : DynaBeeProfile
{
public ResolverProfile() : base("Demo.Resolvers")
{
}
public override void Configure(IBeeAssemblyBuilder builder)
{
var getRequiredService = typeof(ServiceProviderServiceExtensions)
.GetMethods()
.Single(x => x.Name == nameof(ServiceProviderServiceExtensions.GetRequiredService)
&& x.IsGenericMethodDefinition
&& x.GetParameters().Length == 1)
.MakeGenericMethod(typeof(OrderTotalTextResolver));
var resolveMethod = typeof(IValueResolver<Order, OrderDto, string>)
.GetMethod(nameof(IValueResolver<Order, OrderDto, string>.Resolve))!;
builder.AddClass("OrderMapper", c => c
.AddMethod("Map", typeof(OrderDto), m => m
.WithParameter<Order>("source")
.WithParameter<IMapContext>("mapContext")
.EmitsBody(body =>
{
var source = body.Parameter<Order>("source");
var mapContext = body.Parameter<IMapContext>("mapContext");
var destination = body.DeclareLocal<OrderDto>("destination");
var resolver = body.DeclareLocal<OrderTotalTextResolver>("resolver");
body.Assign(destination, body.New<OrderDto>());
body.Assign(
resolver,
body.StaticCall(
getRequiredService,
body.Property(mapContext, nameof(IMapContext.Services))));
body.Assign(
body.Property(destination, nameof(OrderDto.TotalText)),
body.Call(resolver, resolveMethod, source, destination, mapContext));
body.Return(destination);
})));
}
}
public interface IMapContext
{
IServiceProvider Services { get; }
}
public interface IValueResolver<in TSource, in TDestination, out TMember>
{
TMember Resolve(TSource source, TDestination destination, IMapContext context);
}
public sealed class OrderTotalTextResolver
: IValueResolver<Order, OrderDto, string>
{
public string Resolve(Order source, OrderDto destination, IMapContext context)
=> source.Total.ToString("C");
}
Generated methods can also call collaborators stored on the generated instance:
builder.AddClass("OrderMapper", c => c
.AddAutoProperty<IOrderFormatter>("Formatter")
.AddMethod("Format", typeof(string), m => m
.WithParameter<Order>("source")
.EmitsBody(body =>
{
var formatter = body.Property(body.Self(), "Formatter");
var source = body.Parameter<Order>("source");
var format = typeof(IOrderFormatter).GetMethod(nameof(IOrderFormatter.Format))!;
body.Return(body.Call(formatter, format, source));
})));
7) Collection method bodies
Collection-oriented generated methods can use loops, ordered comparisons, indexed access, runtime-sized arrays, and constructor calls with arguments. This lets integrations generate array/list mapping logic without helper delegates, reflection invocation, expression compilation, or raw IL.
public sealed class CollectionProfile : DynaBeeProfile
{
public CollectionProfile() : base("Demo.Collections")
{
}
public override void Configure(IBeeAssemblyBuilder builder)
{
builder.AddClass("ArrayCopier", c => c
.AddMethod("Copy", typeof(int[]), m => m
.WithParameter<int[]>("source")
.EmitsBody(body =>
{
var source = body.Parameter<int[]>("source");
var destination = body.DeclareLocal<int[]>("destination");
var index = body.DeclareLocal<int>("i");
body.If(body.IsNull(source), whenTrue: branch =>
{
branch.Return(branch.Constant(null, typeof(int[])));
});
body.Assign(
destination,
body.NewArray<int>(body.Property(source, nameof(Array.Length))));
body.For(
initialize: loop => loop.Assign(index, loop.Constant(0)),
condition: loop => loop.LessThan(
index,
loop.Property(source, nameof(Array.Length))),
increment: loop => loop.Assign(
index,
loop.Add(index, loop.Constant(1))),
body: loop => loop.Assign(
loop.Index(destination, index),
loop.Index(source, index)));
body.Return(destination);
})));
}
}
The same primitives can generate list transformations with per-item method calls:
var addMethod = typeof(List<OrderItemDto>)
.GetMethod(nameof(List<OrderItemDto>.Add))!;
var mapMethod = typeof(IItemMapper)
.GetMethod(nameof(IItemMapper.Map))!;
builder.AddClass("ItemMapperAdapter", c => c
.AddMethod("MapItems", typeof(List<OrderItemDto>), m => m
.WithParameter<List<OrderItem>>("source")
.WithParameter<IItemMapper>("mapper")
.EmitsBody(body =>
{
var source = body.Parameter<List<OrderItem>>("source");
var mapper = body.Parameter<IItemMapper>("mapper");
var destination = body.DeclareLocal<List<OrderItemDto>>("destination");
var index = body.DeclareLocal<int>("i");
body.If(body.IsNull(source), whenTrue: branch =>
{
branch.Return(branch.Constant(null, typeof(List<OrderItemDto>)));
});
body.Assign(
destination,
body.New(
typeof(List<OrderItemDto>),
body.Property(source, nameof(List<OrderItem>.Count))));
body.For(
initialize: loop => loop.Assign(index, loop.Constant(0)),
condition: loop => loop.LessThan(
index,
loop.Property(source, nameof(List<OrderItem>.Count))),
increment: loop => loop.Assign(
index,
loop.Add(index, loop.Constant(1))),
body: loop => loop.Evaluate(loop.Call(
destination,
addMethod,
loop.Call(mapper, mapMethod, loop.Index(source, index)))));
body.Return(destination);
})));
For non-indexed sources such as IEnumerable<T>, use ForEach(...). DynaBee
emits the enumerator pattern and disposes the enumerator when enumeration ends.
var addMethod = typeof(List<string>)
.GetMethod(nameof(List<string>.Add))!;
builder.AddClass("EnumerableCopier", c => c
.AddMethod("Copy", typeof(List<string>), m => m
.WithParameter<IEnumerable<string>>("source")
.EmitsBody(body =>
{
var source = body.Parameter<IEnumerable<string>>("source");
var destination = body.DeclareLocal<List<string>>("destination");
body.Assign(destination, body.New<List<string>>());
body.ForEach(source, "item", (item, loop) =>
{
loop.Evaluate(loop.Call(destination, addMethod, item));
});
body.Return(destination);
})));
Method bodies can also express richer computed values without falling back to raw IL:
builder.AddClass("ExpressionMapper", c => c
.AddMethod("Compute", typeof(int), m => m
.WithParameter<int>("x")
.WithParameter<int>("y")
.EmitsBody(body =>
{
var x = body.Parameter<int>("x");
var y = body.Parameter<int>("y");
body.Return(body.Add(
body.Multiply(body.Subtract(x, y), body.Constant(2)),
body.Modulo(x, y)));
}))
.AddMethod("NameOrDefault", typeof(string), m => m
.WithParameter<string>("name")
.EmitsBody(body =>
{
body.Return(body.Coalesce(
body.Parameter<string>("name"),
body.Constant("Unknown")));
})));
8) Generated dispatch delegates
When callers know the delegate shape they want, DynaBee can create typed delegates for generated methods and constructors. Method lookup happens once, then repeated calls use the compiled delegate path instead of reflection invocation.
using DynaBee.FluentApi.Invocation;
var context = catalog.GetContext("Demo.Runtime");
var adder = context.CreateInstance("GeneratedAdder");
var add = context.CreateBoundDelegate<Func<int, int, int>>(
"GeneratedAdder",
adder,
"Add",
new[] { typeof(int), typeof(int) });
var result = add(1, 2); // 3
Open delegates keep the generated instance as the first delegate parameter:
var openAdd = context.CreateOpenDelegate<Func<object, int, int, int>>(
"GeneratedAdder",
"Add",
new[] { typeof(int), typeof(int) });
var result = openAdd(adder, 1, 2);
Constructor factories avoid consumer-side reflection when creating generated instances with constructor arguments:
var createGreeter = context.CreateFactoryDelegate<Func<string, object>>(
"GeneratedGreeter",
new[] { typeof(string) });
var greeter = createGreeter("Ada");
Consumers that discover delegate types at runtime can still let DynaBee own delegate creation:
var delegateType = typeof(Func<int, int, int>);
var add = (Func<int, int, int>)context.CreateBoundDelegate(
delegateType,
"GeneratedAdder",
adder,
"Add",
new[] { typeof(int), typeof(int) });
For diagnostics, tracing, and cache keys, generated methods can be described with stable metadata:
var descriptor = context.GetGeneratedMethodDescriptor(
"GeneratedAdder",
"Add",
new[] { typeof(int), typeof(int) });
Console.WriteLine($"{descriptor.DeclaringType.Name}.{descriptor.Name}");
Object adapters are available for dynamic fallback paths without consumer-side
reflection invocation. Fixed-arity adapters avoid per-call object[]
allocation for common hot paths:
var addAdapter = context.CreateObjectAdapter2(
"GeneratedAdder",
adder,
"Add",
new[] { typeof(int), typeof(int) });
var sum = addAdapter(1, 2); // boxed 3
For higher arity, use an argument-list adapter with stable method metadata:
var adapter = context.CreateArgumentListAdapter(
"GeneratedAggregator",
aggregator,
"Sum",
new[]
{
typeof(int), typeof(int), typeof(int), typeof(int), typeof(int),
typeof(int), typeof(int), typeof(int), typeof(int), typeof(int)
});
var total = adapter.Invoke(new object[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
9) Cached method invokers
DynaBee can create cached invokers for generated methods. The invoker resolves
reflection metadata once, compiles a dispatch bridge, and avoids MethodInfo.Invoke(...)
during repeated calls.
using DynaBee.FluentApi.Invocation;
var mapper = context.CreateInstance("UserToUserDtoMapper");
var invoker = context.CreateBoundMethodInvoker(
"UserToUserDtoMapper",
mapper,
"Map",
new[] { typeof(User), typeof(IMapContext) });
var result = invoker.Invoke(new object[] { user, mapContext });
Multi-source methods use the same API:
var invoker = context.CreateBoundMethodInvoker(
"OrderCustomerToOrderDtoMapper",
mapper,
"Map",
new[] { typeof(Order), typeof(Customer), typeof(IMapContext) });
var result = invoker.Invoke(new object[] { order, customer, mapContext });
10) Testing generated assemblies
DynaBee.Testing provides a small testing layer for generated assemblies,
generated types, diagnostics, dependency injection registration, and source
snapshots. It does not depend on any application framework-specific package.
using DynaBee.Testing;
using DynaBee.Testing.Assertions;
using DynaBee.Testing.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System.Linq.Expressions;
var services = new ServiceCollection()
.AddDynaBeeTesting();
var provider = services.BuildServiceProvider();
var dynabeeTest = provider.GetRequiredService<IDynaBeeTestGenerator>();
var specification = DynaBeeTestSpecification.Create("Demo.Tests", builder => builder
.AddClass("CreateCustomerCommandHandler", type => type
.Implements<IRequestHandler<CreateCustomerCommand, CustomerCreated>>()
.AddMethod("Handle", typeof(CustomerCreated), method => method
.WithParameter<CreateCustomerCommand>("request")
.EmitsExpression(
(Expression<Func<CreateCustomerCommand, CustomerCreated>>)
(request => new CustomerCreated())))));
var result = await dynabeeTest.GenerateAssemblyAsync(specification);
var assembly = result.Assembly;
result.Diagnostics.ShouldBeEmpty();
var generatedType = assembly.ShouldContainType("CreateCustomerCommandHandler");
generatedType.ShouldImplement(typeof(IRequestHandler<,>));
services.AddGeneratedAssembly(assembly);
result.WriteGeneratedSourcesTo("./snapshots/generated");
Useful assertions include generated assembly existence, generated type existence, constructor shape, implemented interfaces, inherited base types, generic arguments, diagnostics, and source snapshot output.
Real-World Use Cases
1) Plugin systems
Generate adapter types at runtime for plugin contracts discovered dynamically.
2) Multi-tenant applications
Create tenant-specific behavior types (validation rules, policy handlers, mapping profiles) without shipping many static assemblies.
3) Runtime API clients / SDK wrappers
Build strongly-typed runtime clients from metadata or schemas loaded from external systems.
4) Dynamic domain models
Generate entities or value objects from configuration (for example low-code platforms or metadata-driven apps).
5) Test doubles and runtime stubs
Create dynamic implementations for integration testing, custom mocks, or simulation environments.
6) High-performance dispatch layers
Emit optimized execution paths for expression-based pipelines where reflection-only invocation is too expensive.
7) Framework integrations via metadata
Attach typed metadata in Fluent API, then consume it in external packages (for example EF mapping hints like table/column/type, custom serialization hints, validation hints).
8) Metadata-driven EF or API model bootstrapping
Use profiles to group dynamic entity definitions by logical assembly, then resolve the generated IAssemblyContext through IDynaBeeAssemblyCatalog while bootstrapping framework integrations.
9) Descriptor-driven handler generation
Transform normalized descriptors into generated classes that inherit framework base types, forward constructor dependencies, override virtual behavior, and register as runtime handler services.
10) Replaceable generation backends
Keep consumer libraries open to alternate generation strategies by converting their descriptors into DynaBeeGenerationPlan instances and applying those plans through IBeeAssemblyBuilder.
Benchmarks
Command:
dotnet run -c Release -f net8.0 --project benchmarks/DynaBee.Benchmarks/DynaBee.Benchmarks.csproj -- --filter *
Measured results:
| Benchmark | Mean | Allocated |
|---|---|---|
CreateInstance |
90.70 ns | 200 B |
CallViaInterface |
1.52 ns | 0 B |
CallViaReflection |
25.17 ns | 24 B |
BuildClass_NoCache |
276.40 us | 10,569 B |
BuildClass_FromCache |
43.16 ns | 144 B |
Notes:
BuildClass_NoCacheandBuildClass_FromCachewere executed withShortRun.- Cache dramatically reduces repeated build cost.
| 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 is compatible. 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 is compatible. 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. |
-
net10.0
-
net8.0
-
net9.0
NuGet packages (4)
Showing the top 4 NuGet packages that depend on DynaBee:
| Package | Downloads |
|---|---|
|
TurtlePath.Automations
Declarative automation profiles and generated handler registration for TurtlePath application flows. |
|
|
Crabalidator
Crabalidator is a high-performance .NET validation library powered by DynaBee-generated runtime validators. |
|
|
OctoMap
OctoMap is a lightweight .NET object mapping library powered by DynaBee-generated runtime mappers. |
|
|
DynaBee.Testing
Testing helpers for DynaBee generated assemblies, generated types, diagnostics, dependency injection registration, and generated source snapshots. |
GitHub repositories
This package is not used by any popular GitHub repositories.