Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Windsor to automatically subscribe to event aggregator with custom facility

Reading this blog post it mentions you can get your DI container to automatically subscribe to events if it implements IHandle<>. That is exactly what I'm trying to accomplish.

Here is what I have so far.

container.Register(Component
    .For<MainWindowViewModel>()
    .ImplementedBy<MainWindowViewModel>()
    .LifeStyle.Transient
    .OnCreate((kernel, thisType) => kernel.Resolve<IEventAggregator>().Subscribe(thisType)));

While this code is successfully subscribing MainWindowViewModel to receive published messages, come time to actually receive messages nothing happens. If I manually subscribe all works as expected.

Here is my MainWindowViewModel class.

public class MainWindowViewModel : IHandle<SomeMessage>
{
    private readonly FooViewModel _fooViewModel;
    private readonly IEventAggregator _eventAggregator;

    public MainWindowViewModel(FooViewModel fooViewModel, IEventAggregator eventAggregator)
    {
        _fooViewModel = fooViewModel;
        _eventAggregator = eventAggregator;

        //_eventAggregator.Subscribe(this);

        _fooViewModel.InvokeEvent();
    }

    public void Handle(SomeMessage message)
    {
        Console.WriteLine("Received message with text: {0}", message.Text);
    }
}

How can I tell Windsor to automatically subscribe if any class inherits IHandle<>?

I ended up coming up with this custom facility that subscribes.

public class EventAggregatorFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.DependencyResolving += Kernel_DependencyResolving;
    }

    private void Kernel_DependencyResolving(ComponentModel client, DependencyModel model, object dependency)
    {
        if(typeof(IHandle).IsAssignableFrom(client.Implementation))
        {
            var aggregator = Kernel.Resolve<IEventAggregator>();
            aggregator.Subscribe(client.Implementation);
        }
    }
}

Looking at the EventAggregator class provided by Caliburn.Micro I'm able to see that the subcription is successful, however if another class publishes a message the MainWindowViewModel class isn't getting getting handled. Manually subscribing still works but I'd like to automate this process. I have a feeling that it's not subscribing the correct instance. Not sure how to fix that, though.

I've also tried using every other event exposed by the Kernel property. Most of them can't resolve IEventAggregator.

What am I missing?

like image 931
gcso Avatar asked Aug 12 '11 13:08

gcso


2 Answers

"I have a feeling that it's not subscribing the correct instance. Not sure how to fix that, though."

You are subscribing to the type of the implementation (an instance of System.Type), not the actual dependency being resolved. The line:

aggregator.Subscribe(client.Implementation);

should be

aggregator.Subscribe(dependency);
like image 148
asgerhallas Avatar answered Oct 08 '22 15:10

asgerhallas


You probably need to configure your IEventAggregator as a singleton. Not sure exactly how this would be done with Windsor, but with ninject you would do something like

Bind<IEventAggregator>().To<ConcreteEventAggregator>().InSingletonScope()

Having a singleton would ensure that all the events are aggregated into a single underlying dictionary (or the data type of your choice), instead of having a new one created every time you resolve IEventAggregator. HTH.

like image 40
Raghu Avatar answered Oct 08 '22 17:10

Raghu