Registration Builders¶
The MessageRegistrationBuilder provides a structured way to create message registrations with fine-grained control over lifecycle, configuration, and resource cleanup.
This guide covers:
- When to use the builder pattern
- Configuring registrations with options
- Managing lifecycle with leases
- Practical usage examples
Table of Contents¶
- Overview
- MessageRegistrationBuilder
- MessageRegistrationBuildOptions
- MessageRegistrationLease
- MessageRegistrationLifecycle
- Code Examples
- See Also
Overview¶
DxMessaging offers two approaches to message registration:
| Approach | Use Case |
|---|---|
| Direct token creation | Simple scenarios with manual lifecycle management |
| Builder pattern | Complex scenarios requiring DI integration, lifecycle hooks, or structured configuration |
When to use the builder pattern¶
- You need lifecycle callbacks (build, activate, deactivate, dispose)
- You want to integrate with dependency injection containers
- You prefer a more declarative configuration style
- You need to manage multiple registrations as a single unit
When direct token creation is sufficient¶
- Simple MonoBehaviour-based messaging
- No need for lifecycle hooks
- Using
MessagingComponentor similar built-in components
MessageRegistrationBuilder¶
The MessageRegistrationBuilder class creates MessageRegistrationLease instances based on configuration options.
Creating a Builder¶
using DxMessaging.Core.MessageBus;
// Builder that uses global bus resolution
MessageRegistrationBuilder builder = new MessageRegistrationBuilder();
// Builder with a custom provider
IMessageBusProvider provider = new FixedMessageBusProvider(myMessageBus);
MessageRegistrationBuilder builderWithProvider = new MessageRegistrationBuilder(provider);
Building Leases¶
Call Build() with options to create a lease:
MessageRegistrationBuildOptions options = new MessageRegistrationBuildOptions
{
ActivateOnBuild = true,
Configure = token =>
{
_ = token.RegisterUntargeted<PlayerDamaged>(OnPlayerDamaged);
}
};
using MessageRegistrationLease lease = builder.Build(options);
MessageRegistrationBuildOptions¶
Configure how the builder creates registrations using MessageRegistrationBuildOptions.
Owner Configuration¶
Specify who owns the registration:
// Explicit InstanceId owner
options.Owner = new InstanceId(42);
// Unity Object owner (Unity 2021.3+)
options.UnityOwner = gameObject; // or any Component
When omitted, a synthetic owner ID is generated automatically. UnityOwner takes precedence over Owner when both are set.
Message Bus Selection¶
Control which bus handles registrations:
// Use a specific bus directly
options.PreferredMessageBus = myMessageBus;
// Use a provider (falls back if PreferredMessageBus is null)
options.MessageBusProvider = new FixedMessageBusProvider(otherBus);
Resolution order:
PreferredMessageBusif setMessageBusProvider.Resolve()if provider is set- Builder's provider (from constructor) if set
null(uses global bus)
Handler State¶
Control the initial state of handlers:
// Whether the underlying MessageHandler starts active (default: true)
options.HandlerStartsActive = true;
// Whether to call Enable() immediately after building (default: false)
options.ActivateOnBuild = true;
Diagnostics¶
Enable diagnostic mode for debugging:
This sets MessageRegistrationToken.DiagnosticMode to true, enabling detailed logging.
Configure Callback¶
Register handlers immediately after token creation:
options.Configure = token =>
{
_ = token.RegisterUntargeted<GameStarted>(OnGameStarted);
// For targeted messages, provide the target InstanceId
_ = token.RegisterTargeted<DamageMessage>(targetInstanceId, OnDamage);
};
This callback runs after the token is created but before lifecycle hooks and activation.
Note: RegisterTargeted<T> requires an InstanceId target parameter specifying which entity should receive the message. For Unity objects, use RegisterGameObjectTargeted<T> or RegisterComponentTargeted<T> instead.
Lifecycle Hooks¶
Add callbacks for lifecycle events:
options.Lifecycle = new MessageRegistrationLifecycle(
onBuild: token => Debug.Log("Token created"),
onActivate: token => Debug.Log("Token enabled"),
onDeactivate: token => Debug.Log("Token disabled"),
onDispose: token => Debug.Log("Token disposed")
);
MessageRegistrationLease¶
A MessageRegistrationLease wraps the created token and provides lifecycle management.
Properties¶
| Property | Type | Description |
|---|---|---|
Token | MessageRegistrationToken | The underlying registration token |
Handler | MessageHandler | The handler hosting registrations |
MessageBus | IMessageBus | The bus used for registrations |
Owner | InstanceId | The owner identifier |
IsActive | bool | Whether the lease is currently active |
Activation Methods¶
// Enable the token and invoke OnActivate callback
lease.Activate();
// Disable the token and invoke OnDeactivate callback
lease.Deactivate();
Activate()throwsObjectDisposedExceptionif called after disposalDeactivate()is safe to call multiple times or after disposal
Dispose Pattern¶
Leases implement IDisposable:
using MessageRegistrationLease lease = builder.Build(options);
// ... use the lease
// Automatically deactivated and disposed at end of scope
Disposal sequence:
- Calls
Deactivate()if active (triggersOnDeactivate) - Invokes
OnDisposecallback - Marks lease as disposed
MessageRegistrationLifecycle¶
The MessageRegistrationLifecycle struct holds callbacks for each lifecycle stage:
public readonly struct MessageRegistrationLifecycle
{
public MessageRegistrationLifecycle(
Action<MessageRegistrationToken> onBuild,
Action<MessageRegistrationToken> onActivate,
Action<MessageRegistrationToken> onDeactivate,
Action<MessageRegistrationToken> onDispose);
public Action<MessageRegistrationToken> OnBuild { get; }
public Action<MessageRegistrationToken> OnActivate { get; }
public Action<MessageRegistrationToken> OnDeactivate { get; }
public Action<MessageRegistrationToken> OnDispose { get; }
}
Callback Order¶
OnBuild— Immediately after lease creation, before activationOnActivate— WhenActivate()is called (or automatically ifActivateOnBuild = true)OnDeactivate— WhenDeactivate()is called or during disposal while activeOnDispose— DuringDispose(), after deactivation
All callbacks receive the MessageRegistrationToken as a parameter.
Code Examples¶
Basic Builder Usage¶
using DxMessaging.Core.MessageBus;
using UnityEngine;
public sealed class BasicBuilderExample : MonoBehaviour
{
private MessageRegistrationBuilder builder;
private MessageRegistrationLease lease;
private void Awake()
{
builder = new MessageRegistrationBuilder();
MessageRegistrationBuildOptions options = new MessageRegistrationBuildOptions
{
UnityOwner = this,
ActivateOnBuild = true,
Configure = token =>
{
_ = token.RegisterUntargeted<GameEvent>(OnGameEvent);
}
};
lease = builder.Build(options);
}
private void OnDestroy()
{
lease?.Dispose();
}
// Action<T> handler signature (used with RegisterUntargeted<T>(..., Action<T>))
private void OnGameEvent(GameEvent message)
{
Debug.Log($"Received: {message}");
}
// Alternative: FastHandler<T> signature for better performance (avoids boxing)
// private void OnGameEvent(ref GameEvent message)
// {
// Debug.Log($"Received: {message}");
// }
}
DI Integration Pattern¶
using DxMessaging.Core.MessageBus;
using UnityEngine;
public sealed class DIIntegrationExample : MonoBehaviour
{
// Injected by your DI container
private IMessageBusProvider messageBusProvider;
private MessageRegistrationLease lease;
public void Initialize(IMessageBusProvider provider)
{
messageBusProvider = provider;
MessageRegistrationBuilder builder = new MessageRegistrationBuilder(provider);
MessageRegistrationBuildOptions options = new MessageRegistrationBuildOptions
{
UnityOwner = this,
ActivateOnBuild = true,
Configure = ConfigureRegistrations
};
lease = builder.Build(options);
}
private void ConfigureRegistrations(MessageRegistrationToken token)
{
_ = token.RegisterUntargeted<PlayerSpawned>(OnPlayerSpawned);
_ = token.RegisterUntargeted<PlayerDied>(OnPlayerDied);
}
private void OnDestroy()
{
lease?.Dispose();
}
// Action<T> handler signatures
private void OnPlayerSpawned(PlayerSpawned message)
{
Debug.Log($"Player spawned: {message.PlayerId}");
}
private void OnPlayerDied(PlayerDied message)
{
Debug.Log($"Player died: {message.PlayerId}");
}
}
Custom Lifecycle Hooks¶
using DxMessaging.Core.MessageBus;
using UnityEngine;
public sealed class LifecycleHooksExample : MonoBehaviour
{
private MessageRegistrationBuilder builder;
private MessageRegistrationLease lease;
private void Awake()
{
builder = new MessageRegistrationBuilder();
MessageRegistrationBuildOptions options = new MessageRegistrationBuildOptions
{
UnityOwner = this,
HandlerStartsActive = true,
ActivateOnBuild = false, // We'll activate manually
EnableDiagnostics = true,
Configure = token =>
{
_ = token.RegisterUntargeted<LevelLoaded>(OnLevelLoaded);
},
Lifecycle = new MessageRegistrationLifecycle(
onBuild: token => Debug.Log("[Lifecycle] Token built"),
onActivate: token => Debug.Log("[Lifecycle] Activated - now receiving messages"),
onDeactivate: token => Debug.Log("[Lifecycle] Deactivated - paused"),
onDispose: token => Debug.Log("[Lifecycle] Disposed - cleanup complete")
)
};
lease = builder.Build(options);
}
private void OnEnable()
{
// Activate when the component is enabled
lease?.Activate();
}
private void OnDisable()
{
// Deactivate but don't dispose - we might re-enable
lease?.Deactivate();
}
private void OnDestroy()
{
lease?.Dispose();
}
// Action<T> handler signature
private void OnLevelLoaded(LevelLoaded message)
{
Debug.Log($"Level loaded: {message.LevelName}");
}
}
FixedMessageBusProvider¶
For scenarios where you always want to use a specific bus instance:
using DxMessaging.Core.MessageBus;
// Create a provider that always returns a specific bus
IMessageBus myBus = new MessageBus();
IMessageBusProvider provider = new FixedMessageBusProvider(myBus);
// Use with builder
MessageRegistrationBuilder builder = new MessageRegistrationBuilder(provider);
// Or override per-build
MessageRegistrationBuildOptions options = new MessageRegistrationBuildOptions
{
MessageBusProvider = provider,
Configure = token => { /* ... */ }
};
See Also¶
- Message Bus Providers — More on the provider system
- Runtime Configuration — Dynamic reconfiguration options