Frage

I have a couple of newbie starting problems with Rebus. All the nice samples in the Rebus ReadMe file uses Windsor Castle, but I don't have that option; instead I must use Unity.

My first challenge was to find a suitable adapter for the Unity IoC Container, as the example states:

var someContainerAdapter =
    new AdapterForMyFavoriteIocContainer(myFavoriteIocContainer);

I finally found some code here that seems to do the job, but perhaps a better container exist, as I have to implement the IContainerAdapter interface myself (I wonder if that is needed...).

But I can live with that...

My next problem is worse and I haven't found out yet. In the Rebus Getting started-example the following is used to add a handler to the IoC container:

container.Register(
    Component.For<IHandleMessages<DateTime>>()
    .ImplementedBy<PrintDateTime>());

This above is Windsor Castle syntax and I don't know how the Unity syntax should be for the same action. So I need some help here. A suggestion would be if I could get a reference to a small solution that works with Unity.

War es hilfreich?

Lösung

Using unity with Rebus require me to register IHandleMessages the following types

  • SubscriptionMessage
  • IRebusControlMessage
  • object

...since the IContainerAdapter.GetHandlerInstancesFor< T > is called with the above types.

And Im afraid that in not the idea.

I cannot make unity resolve a type using an interface as Key without also specifying the type implementing the interface.

It would be great if one the awesome Rebus contributors could post an example that use Unity.

Andere Tipps

My suggestion is to use Rebus.Unity, which is a ready-to-use Unity container adapter for Rebus, made by one the awesome Rebus contributors.

There's a NuGet package for it, so you could just install-package Rebus.Unity (or whichever way is your preferred way of adding NuGet packages to your project).

Now, in order to register handlers with Unity, you should be aware of the fact that Unity behaves differently than all the other containers out there regarding ResolveAll behavior (at least the ones that I know about), which requires that all of your handlers are registered as named registrations.

I don't remember the exact Unity syntax to do this, but I think it looks somewhat like this:

container.RegisterType<IHandleMessages<SomeMessage>, MyMessageHandler>("id");

in order to register MyMessageHandler as a handler of SomeMessage. There's several other overloads of the various registration functions, so you should be able to find one that fits your needs - but keep in mind that with Unity, since Rebus does a ResolveAll, you must always register handlers with a key/id.

As mentioned above Unity does only resolve the type requested, it does not look for inherited classes or interfaces.

There is a way to use Unity with polymorphic resolve though if you implement a UnityExtension that uses reflection to find the implementations you are after. We needed a Rebus adapter for unity with polymorphic capabilities and the methods Register<> and Handle<>.

Here is our version of Rebus using Unity which works nicely.

public class UnityContainerAdapter : IContainerAdapter, IDisposable {
public IBus Bus { get; internal set; }

private readonly IUnityContainer _unityContainer;
private readonly IHandlerRegistrator _handlerRegistrator;

public UnityContainerAdapter(IUnityContainer unityContainer)
{
    _unityContainer = unityContainer;

    _handlerRegistrator = _unityContainer
        .AddNewExtension<AllThatImplements>()
        .Configure<IHandlerRegistrator>();
}

public IEnumerable<IHandleMessages> GetHandlerInstancesFor<T>()
{
    return _unityContainer.ResolveAll<IHandleMessages<T>>();
}

public void Release(IEnumerable handlerInstances)
{
    foreach (IDisposable disposable in handlerInstances.OfType<IDisposable>())
        disposable.Dispose();
}

public void SaveBusInstances(IBus bus)
{
    Bus = bus;
    _unityContainer.RegisterInstance(typeof(IBus), bus);
    _unityContainer.RegisterType<IMessageContext>(new InjectionMember[1]
    {
        new InjectionFactory(c => (object) MessageContext.GetCurrent())
    });
}

public UnityContainerAdapter Register<THandler>()
{
    _handlerRegistrator.RegisterImplementingType<THandler>(typeof(IHandleMessages<>));
    return this;
}

public UnityContainerAdapter Handle<TMessage>(Action<TMessage> handler)
{
    _unityContainer.RegisterType<IHandleMessages<TMessage>, HandlerMethodWrapper<TMessage>>(Guid.NewGuid().ToString(), new InjectionConstructor(handler));
    return this;
}

internal class HandlerMethodWrapper<T> : IHandleMessages<T>
{
    private readonly Action<T> _action;

    public HandlerMethodWrapper(Action<T> action)
    {
        _action = action;
    }

    public void Handle(T message)
    {
        _action(message);
    }
}

public void Dispose()
{
    _unityContainer.Dispose();
}

#region - Unity Extionsion -
internal class AllThatImplements : UnityContainerExtension, IHandlerRegistrator
{
    protected override void Initialize() { }

    public void RegisterImplementingType<T>(Type implementationToLookFor)
    {
        var closedType = typeof(T);

        closedType.GetInterfaces()
                  .Where(x => x.IsGenericType)
                  .Where(x => x.GetGenericTypeDefinition() == implementationToLookFor)
                  .ToList()
                  .ForEach(x => Container.RegisterType(x, closedType, Guid.NewGuid().ToString()));
    }
}

internal interface IHandlerRegistrator : IUnityContainerExtensionConfigurator
{
    void RegisterImplementingType<T>(Type inheritedTypeToLookFor);
}
#endregion

}

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top