Skip to content

v4.0.0

Latest
Compare
Choose a tag to compare
@github-actions github-actions released this 18 Sep 13:19
· 3 commits to main since this release

LiteBus v4.0 Release Notes

LiteBus v4 is a major release that introduces a fundamental architectural redesign, powerful new features, and significant improvements to flexibility and extensibility. The core focus of this release is to decouple the library from specific Dependency Injection (DI) containers, introduce a durable Command Inbox for guaranteed processing, and provide advanced control over event mediation.

🚀 New Features

1. Dependency Injection Abstraction (LiteBus.Runtime)

The entire library has been refactored to be DI-agnostic. A new set of core projects (LiteBus.Runtime and LiteBus.Runtime.Abstractions) provides a common foundation. LiteBus now integrates with DI containers via a lightweight adapter pattern.

  • DI-Agnostic Modules: CommandModule, QueryModule, and EventModule no longer depend on a specific DI container. They build against the new IModuleConfiguration and IDependencyRegistry abstractions.
  • Improved Encapsulation: Modules now only register the handlers they discover, preventing redundant DI registrations and improving startup performance.

2. First-Class Autofac Support

Alongside the existing Microsoft Dependency Injection support, LiteBus v4 now offers a dedicated integration package for Autofac.

  • New Package: LiteBus.Extensions.Autofac provides seamless integration.
  • Consistent API: The registration API (builder.AddLiteBus(...)) is consistent with the Microsoft DI extension.

3. Durable Command Inbox

A new Command Inbox feature has been added to support durable, out-of-process, or deferred command execution. This is ideal for ensuring command processing in distributed systems or long-running workflows.

  • [StoreInInbox] Attribute: Decorate any ICommand class with this attribute to automatically divert it to a durable store instead of immediate processing.
  • Core Abstractions: ICommandInbox, ICommandInboxProcessor, and ICommandInboxBatch provide the contracts for implementing a custom inbox store and processor.
  • Hosted Service: CommandInboxProcessorHostedService provides a ready-to-use IHostedService for processing inbox commands in the background.

4. Advanced Event Mediation Control

Event mediation has been completely overhauled to provide granular control over handler execution.

  • Handler Execution Priority: The new [HandlerPriority(priority)] attribute replaces [HandlerOrder]. Handlers are grouped by priority, with lower numbers executing first.
  • Configurable Concurrency: EventMediationSettings now includes an Execution property to control concurrency at two levels:
    • PriorityGroupsConcurrencyMode: Run different priority groups sequentially or in parallel.
    • HandlersWithinSamePriorityConcurrencyMode: Run handlers within the same priority group sequentially or in parallel.
  • Powerful Handler Filtering: The HandlerPredicate now receives a full IHandlerDescriptor, allowing for advanced filtering based on handler type, priority, tags, and message type.

✨ Improvements

  • Simplified Module Registration: The AddCommandModule, AddEventModule, and AddQueryModule extension methods will now automatically register the core MessageModule if it hasn't been registered, reducing boilerplate configuration.
  • Robust Message & Handler Registry: The internal MessageRegistry has been re-engineered for better performance and correctness, ensuring handlers are correctly associated with messages regardless of registration order.
  • Clearer API: Many interfaces and classes have been renamed for better clarity and intent (e.g., Handlers -> MainHandlers, Order -> Priority).
  • New IMessageRegistry.Clear() method: Useful for test environments to ensure a clean state between test runs.

💥 Breaking Changes

This is a major release with significant architectural changes. Please follow the migration guide below carefully.

  1. Project Structure & NuGet Packages: The project structure has been refactored. You will need to update your package references.
  2. DI Registration: The AddLiteBus registration process has changed.
  3. HandlerOrderAttribute is now HandlerPriorityAttribute: The attribute and its Order property have been renamed to Priority.
  4. IMessageDependencies Properties Renamed: Handlers and IndirectHandlers are now MainHandlers and IndirectMainHandlers. This primarily affects custom mediation strategies.
  5. Context Items Dictionary Key Type: The key for the Items dictionary on ExecutionContext, CommandMediationSettings, and QueryMediationSettings has been changed from object to string for better type safety and consistency.
  6. EventMediationSettings Redesigned: The structure of EventMediationSettings has been completely changed to support advanced priority and concurrency features.

Migration Guide from v3 to v4

Follow these steps to upgrade your project to LiteBus v4.

Step 1: Update NuGet Packages

The package structure has been reorganized. You will need to remove old packages and add new ones.

1. Remove old packages:

  • LiteBus.Extensions.MicrosoftDependencyInjection
  • LiteBus.Commands.Extensions.MicrosoftDependencyInjection
  • LiteBus.Events.Extensions.MicrosoftDependencyInjection
  • LiteBus.Queries.Extensions.MicrosoftDependencyInjection

2. Add new packages:

For Microsoft.Extensions.DependencyInjection:

  • LiteBus.Extensions.Microsoft.DependencyInjection
  • LiteBus.Commands.Extensions.Microsoft.DependencyInjection
  • LiteBus.Events.Extensions.Microsoft.DependencyInjection
  • LiteBus.Queries.Extensions.Microsoft.DependencyInjection

For Autofac:

  • LiteBus.Extensions.Autofac
  • LiteBus.Commands.Extensions.Autofac
  • LiteBus.Events.Extensions.Autofac
  • LiteBus.Queries.Extensions.Autofac

Step 2: Update AddLiteBus Registration

The registration API has been streamlined. The AddLiteBus method is now in LiteBus.Extensions.Microsoft.DependencyInjection or LiteBus.Extensions.Autofac. The module-specific extensions (AddCommandModule, etc.) are now located in their respective core projects.

Before (v3):

// using LiteBus.Messaging.Extensions.MicrosoftDependencyInjection;
// using LiteBus.Commands.Extensions.MicrosoftDependencyInjection;

services.AddLiteBus(modules =>
{
    modules.AddMessageModule(msg => msg.RegisterFromAssembly(typeof(MyHandler).Assembly));
    modules.AddCommandModule(cmd => cmd.RegisterFromAssembly(typeof(MyCommand).Assembly));
});

After (v4):
The core MessageModule is now added automatically if not present.

// using LiteBus.Extensions.Microsoft.DependencyInjection;
// using LiteBus.Commands; // Note the namespace change

services.AddLiteBus(modules =>
{
    // No need to add MessageModule unless you have specific global handlers to register.
    // It will be added automatically by AddCommandModule.
    modules.AddCommandModule(cmd => cmd.RegisterFromAssembly(typeof(MyCommand).Assembly));
});

If you need to configure the MessageModule explicitly, ensure it is called first:

services.AddLiteBus(modules =>
{
    modules.AddMessageModule(msg => msg.Register(typeof(MyGlobalErrorHandler)));
    modules.AddCommandModule(cmd => cmd.RegisterFromAssembly(typeof(MyCommand).Assembly));
    modules.AddEventModule(evt => evt.RegisterFromAssembly(typeof(MyEvent).Assembly));
});

Step 3: Rename HandlerOrderAttribute to HandlerPriorityAttribute

This is a direct name change. You can perform a project-wide find and replace.

Before (v3):

[HandlerOrder(1)]
public class MyHandler : ICommandHandler<MyCommand>
{
    // ...
}

After (v4):

using LiteBus.Messaging.Abstractions;

[HandlerPriority(1)]
public class MyHandler : ICommandHandler<MyCommand>
{
    // ...
}

Step 4: Update Items Dictionary Key

The key type for the Items collection on mediation settings and execution context has been changed from object to string.

Before (v3):

var settings = new CommandMediationSettings();
var myKey = new object();
settings.Items[myKey] = "my-value";

// In a handler:
var myValue = AmbientExecutionContext.Current.Items[myKey];

After (v4):

var settings = new CommandMediationSettings();
settings.Items["my-key"] = "my-value";

// In a handler:
var myValue = AmbientExecutionContext.Current.Items["my-key"];

Step 5: Update EventMediationSettings

The structure of EventMediationSettings has been completely redesigned to support the new execution features.

Before (v3):
The old settings were flat and had a simple handler predicate.

var settings = new EventMediationSettings
{
    ThrowIfNoHandlerFound = true,
    Filters = 
    {
        Tags = new[] { "tag1" },
        HandlerPredicate = type => type.Namespace.StartsWith("MyProject.Core")
    }
};

await eventMediator.PublishAsync(myEvent, settings);

After (v4):
The settings are now split into Routing and Execution. The HandlerPredicate is more powerful, receiving the full IHandlerDescriptor.

var settings = new EventMediationSettings
{
    ThrowIfNoHandlerFound = true,
    Routing =
    {
        Tags = new[] { "tag1" },
        // The predicate now receives the full descriptor
        HandlerPredicate = descriptor => descriptor.HandlerType.Namespace.StartsWith("MyProject.Core")
    },
    Execution =
    {
        // New concurrency controls
        PriorityGroupsConcurrencyMode = ConcurrencyMode.Sequential,
        HandlersWithinSamePriorityConcurrencyMode = ConcurrencyMode.Parallel
    }
};

await eventMediator.PublishAsync(myEvent, settings);

Step 6: Update Custom Mediation Strategies (Advanced)

If you have implemented a custom IMessageMediationStrategy, you will need to update it to use the renamed properties on IMessageDependencies.

Before (v3):

public TResult Mediate(TMessage message, IMessageDependencies messageDependencies, ...)
{
    var mainHandler = messageDependencies.Handlers.Single();
    var indirectHandlers = messageDependencies.IndirectHandlers;
    // ...
}

After (v4):

public TResult Mediate(TMessage message, IMessageDependencies messageDependencies, ...)
{
    var mainHandler = messageDependencies.MainHandlers.Single();
    var indirectHandlers = messageDependencies.IndirectMainHandlers;
    // ...
}