Repository navigation
Integrations Reflex
Use Reflex for object construction and DxMessaging for message delivery. The optional
DxMessaging Reflex assembly registers both MessageBus and IMessageBus, and it can provide
IMessageRegistrationBuilder to container-created services.
Changed in v3.2.3: The examples target Reflex 14.0 or newer. DxMessaging's registration helpers also adapt to the pre-14
AddSingletonAPI.
- Install DxMessaging through UPM.
- Install Reflex 14.0 or newer (
com.gustavopsantos.reflex). - Create a Reflex settings asset inside a
Resourcesfolder with Assets > Create > Reflex > Settings.
Reflex discovers IInstaller components below a ContainerScope. Derive the installer from
MonoBehaviour so it can be attached to that hierarchy.
using DxMessaging.Unity.Integrations.Reflex;
using Reflex.Core;
using UnityEngine;
public sealed class DxMessagingInstaller : MonoBehaviour, IInstaller
{
public void InstallBindings(ContainerBuilder builder)
{
builder.AddDxMessagingBus();
new DxMessagingRegistrationInstaller().InstallBindings(builder);
}
}AddDxMessagingBus() uses an explicit factory and exposes the same singleton as both
MessageBus and IMessageBus. DxMessagingRegistrationInstaller adds
IMessageRegistrationBuilder.
- Create a scene scope with GameObject > Reflex > SceneScope.
- Add
DxMessagingInstallerto theSceneScopeGameObject or one of its children. - Enter Play Mode. Reflex builds the scene container and injects scene objects from it.
For one bus shared across scenes, put the installer on a Reflex RootScope prefab and add that
prefab to the RootScopes list in the Reflex settings asset.
The following service owns a MessageRegistrationLease. Its constructor stages a real
handler, Initialize() activates it, and Dispose() releases it.
using System;
using DxMessaging.Core.Attributes;
using DxMessaging.Core.MessageBus;
[DxBroadcastMessage]
[DxAutoConstructor]
public readonly partial struct PlayerDamaged
{
public readonly int damage;
}
public sealed class DamageService : IDisposable
{
private readonly MessageRegistrationLease _lease;
public DamageService(IMessageRegistrationBuilder registrationBuilder)
{
MessageRegistrationBuildOptions options = new()
{
Configure = token =>
{
_ = token.RegisterBroadcastWithoutSource<PlayerDamaged>(OnPlayerDamaged);
},
};
_lease = registrationBuilder.Build(options);
}
public int LastDamage { get; private set; }
public void Initialize()
{
_lease.Activate();
}
public void Dispose()
{
_lease.Dispose();
}
private void OnPlayerDamaged(DxMessaging.Core.InstanceId player, PlayerDamaged message)
{
LastDamage = message.damage;
}
}Register the service with Reflex 14's singleton and lazy-resolution settings:
using Reflex.Enums;
builder.RegisterType(
typeof(DamageService),
Lifetime.Singleton,
Resolution.Lazy
);Reflex disposes singleton services with their owning container. Call Initialize() from a
bootstrap component after resolving the service. Reflex does not provide an IInitializable
lifecycle contract.
Inject the container bus before MessagingComponent registers its handlers:
using DxMessaging.Core.MessageBus;
using DxMessaging.Unity;
using Reflex.Attributes;
using UnityEngine;
[DisallowMultipleComponent]
[RequireComponent(typeof(MessagingComponent))]
public sealed class MessagingComponentConfigurator : MonoBehaviour
{
[Inject]
private IMessageBus _messageBus;
private void Awake()
{
GetComponent<MessagingComponent>().Configure(
_messageBus,
MessageBusRebindMode.RebindActive
);
}
}Add this configurator beside each MessagingComponent that should use the container-owned bus.
Reflex's scene scope runs before ordinary Awake() methods and injects the field first.
Inject IMessageBus into a component that only emits messages:
using DxMessaging.Core.Extensions;
using DxMessaging.Core.MessageBus;
using Reflex.Attributes;
using UnityEngine;
public sealed class GameBootstrap : MonoBehaviour
{
[Inject]
private IMessageBus _messageBus;
private void Start()
{
GameStarted message = new();
_messageBus.EmitUntargeted(ref message);
}
}Reflex injects scene objects when it creates the scene container. Inject objects instantiated
later through GameObjectInjector before returning them to callers:
using System.Collections.Generic;
using Reflex.Core;
using Reflex.Injectors;
using UnityEngine;
public sealed class EnemyPool
{
private readonly Container _container;
private readonly Enemy _enemyPrefab;
private readonly Queue<Enemy> _pool = new();
public EnemyPool(Container container, Enemy enemyPrefab)
{
_container = container;
_enemyPrefab = enemyPrefab;
}
public Enemy Spawn()
{
if (_pool.Count > 0)
{
return _pool.Dequeue();
}
Enemy enemy = UnityEngine.Object.Instantiate(_enemyPrefab);
GameObjectInjector.InjectObject(enemy.gameObject, _container);
return enemy;
}
public void Return(Enemy enemy)
{
_pool.Enqueue(enemy);
}
}Build an isolated container with a real bus and the same DxMessaging installer used at runtime:
using DxMessaging.Core.MessageBus;
using DxMessaging.Unity.Integrations.Reflex;
using NUnit.Framework;
using Reflex.Core;
using Reflex.Enums;
[TestFixture]
public sealed class DamageServiceTests
{
[Test]
public void InitializeListensToMessages()
{
ContainerBuilder builder = new();
MessageBus bus = new();
builder.RegisterValue(
bus,
new[] { typeof(MessageBus), typeof(IMessageBus) }
);
new DxMessagingRegistrationInstaller().InstallBindings(builder);
builder.RegisterType(
typeof(DamageService),
Lifetime.Singleton,
Resolution.Lazy
);
using Container container = builder.Build();
DamageService service = container.Resolve<DamageService>();
service.Initialize();
PlayerDamaged message = new(25);
DxMessaging.Core.InstanceId player = new(42);
bus.SourcedBroadcast(ref player, ref message);
Assert.That(service.LastDamage, Is.EqualTo(25));
}
}- Install DxMessaging and Reflex.
- Create a Reflex settings asset under
Resources. - Create a
ContainerScopeand attach anIInstallercomponent. - Call
AddDxMessagingBus()and installDxMessagingRegistrationInstaller.
- Register container services with a concrete Reflex lifetime and resolution mode.
- Activate builder-created leases from a bootstrap component.
- Dispose leases directly or let Reflex dispose their singleton owner.
- Configure each existing
MessagingComponentwith the injected bus.
- Inject runtime-created GameObjects with
GameObjectInjectorbefore use. - Build a fresh
ContainerBuilderandMessageBusfor each test. - Register real handlers and assert their observable result.
- Integrations-Zenject -- Zenject container wiring
- Integrations-Vcontainer -- VContainer lifetime scopes
- Getting-Started -- all DxMessaging guides
- Getting-Started-Overview
- Getting-Started-Getting-Started
- Getting-Started-Install
- Getting-Started-Quick-Start
- Getting-Started-Visual-Guide
- Concepts-Message-Types
- Concepts-Listening-Patterns
- Concepts-Targeting-And-Context
- Concepts-Interceptors-And-Ordering
- Guides-Patterns
- Guides-Unity-Integration
- Guides-Testing
- Guides-Diagnostics
- Guides-Advanced
- Guides-Migration-Guide
- Advanced-Emit-Shorthands
- Advanced-Message-Bus-Providers
- Advanced-Runtime-Configuration
- Advanced-String-Messages
- Reference-Reference
- Reference-Quick-Reference
- Reference-Helpers
- Reference-Faq
- Reference-Glossary
- Reference-Troubleshooting
- Reference-Compatibility
Links