-
Notifications
You must be signed in to change notification settings - Fork 24
Using Membus
The provided way to start a MemBus instance is going through the BusSetup.
var _bus = BusSetup.StartWith<Conservative>().Construct();
Conservative is one of the already available Configurators contained in the "Configurators" namespace.
As you can see from such a setup, what MemBus needs as a minimum is a default publish pipeline, a default subscriptionresolver, and a default strategy what to do with new subscriptions.
The _bus that is now set up, is of type IBus. IBus derives from IPublisher and ISubscriber. This is due to the "I" in SOLID, so you can use the interface you really need (some of your code may only publish, other parts may need only subscribing features)
//Now you can do something like that: using (_bus.Subscribe((Foo x) => Console.Writeline(x.Text))) { _bus.Publish(new Foo("hello world")); }
Any subscription operation you undertake returns something of type IDisposable. So far MemBus does not do funny WeakDelegate stuff, however, this may come at some point. For now, I am happy about disposing of resources explicitly.
Publish/Subscribe message matching is by default done on the type of the message. Please note that message subscription is contravariant. I.e. a Method accepting a message of type object, will receive all messages published on MemBus.
There are no other rules apart from the following:
- Subscriptions match the
Action<T>
delegate - There are no other rules apart from the previous
If you look at the Subscribe signature, there are a couple of overloads that help you in your messaging needs:
// Only get messages of type MessageB where the Id is "A" b.Subscribe(msg => received++, c=>c.SetFilter(msg=>msg.Id == "A")); // Receive MessageB on the DispatcherThread b.Subscribe(msg => received++, c=>c.DispatchOnUiThread());
However, much of that functionality can be obtained more elegantly via IObservable instances.
It can be quite useful to obtain an IObservable<T>
from your bus. There are 2 ways to do so:
var observable = _bus.Observe<FooMessage>();
or if you want to delegate observable construction to your container of choice, you could do what that method does for you:
var observable = new MessageObservable<T>(_bus);
This allows you to bring the Rx tastiness on top of the IObservable interface.
You may notice that one Subscribe overload accepts any object. This works when you setup MemBus with the FlexibleSubscribeAdapter:
_bus = BusSetup.StartWith<Conservative>() .Apply<FlexibleSubscribeAdapter>(a => a.ByMethodName("Handle")) .Construct() class Subscriber { public void Handle(Foo msg) {} } var disposabble = _bus.Subscribe(new Subscriber());
The FlexibleSubscribeAdapter allows you to set up the convention by which subscibing methods are picked up. The configuration allows wiring up "ByMethodName(string)" or "ByInterface(Type)". The interface may be generic, in that case you specify the open generic. The one rule of subscribing also applies in this scenario: Your subscriptions must match the Action<T>
signature.
The IDisposable returned by the Subcribe(object) disposes of all subscriptions that were found on said object.
If your object implements IAcceptsDisposeToken, the disposable that is returned by the subscribe call will be passed into the object being subscribed. That way objects have a way to take themselves out of the messaging, e.g. when they handle a couple of messages only relevant in a limited time of your App.
There isn't a lot one can say about Publishing. You may pass any object instance into the "Publish" method.
##Publishing to a DI Container
One use case of using MemBus is to dispatch handling of a message to an IOC container. Given a message, the implementation of some type is looked up, instantiated by the container and the message is delivered to the handling method.
In order to do that you need to configure MemBus with the IocSupport option:
_bus = BusSetup
.StartWith<Conservative>()
.Apply<IoCSupport>(s => s.SetAdapter(_testAdapter).SetHandlerInterface(typeof(GimmeMsg<>)))
.Construct();
The Adapter is some instance that needs to implement IocAdapter. Implement this interface to bridge the request to your container of choice. The interface is very straightforward:
public interface IocAdapter
{
IEnumerable<object> GetAllInstances(Type desiredType);
}
Secondly, you declare the interface that will be requested from the IoCContainer. You need to apply the following rules with regard to the chosen interface:
- It needs to be generic with one type argument
- It provides a single void method with one argument. The argument type typically corresponds with the generic type argument.
Here is a working example implementation:
public interface GimmeMsg<in T> { void Gimme(T msg); }