rebus-org / Rebus.ServiceProvider

:bus: Microsoft Extensions Dependency Injection container adapter for Rebus
https://mookid.dk/category/rebus
Other
68 stars 32 forks source link

Implement IHandleMessages<> in existing singleton #15

Closed srollinet closed 6 years ago

srollinet commented 6 years ago

Hello,

I try to make an existing registered singleton implement IHandleMessages<> How to register it correctly?

services.AddSingleton<IHostedService, MyService>();
services.AddSingleton<IHandleMessages<MyMessage>>(x => x.GetService<MyService>()); //Throws an exception when message is sent
//services.AutoRegisterHandlersFromAssemblyOf<MyService>(); //Creates a new instance everytime
services.AddRebus(configure => configure
    .Logging(l => l.Console())
    .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "Local"))
    .Routing(r => r.TypeBased().Map<MyMessage>("Local"))
);

If I register it via services.AutoRegisterHandlersFromAssemblyOf<MyService>(); a new instance is created everytime. If I register it manually via services.AddSingleton<IHandleMessages<MyMessage>>(x => x.GetService<MyService>()); I have an exception when the message is sent

Value cannot be null. Parameter name: handler at Rebus.Pipeline.Receive.HandlerInvoker1..ctor(Func1 action, Object handler, ITransactionContext transactionContext) at Rebus.Pipeline.Receive.ActivateHandlersStep.<>c__DisplayClass4_01.<GetHandlerInvokers>b__0(IHandleMessages1 handler) at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at Rebus.Pipeline.Receive.ActivateHandlersStep.d__4`1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

Is this a bad idea to try to use an existing singleton? I can probably add a new class that implements the handler and where I inject my singleton service. But if it is possible I would like to avoid it.

mookid8000 commented 6 years ago

Is this a bad idea to try to use an existing singleton?

Yes πŸ˜„

Generally, it just makes the world easier to live in, when handlers and injected services are transient.

And then, once in a while, you need to register a singleton, but then please remember that everything that singleton gets injected gets scoped to the lifestyle of the singleton, meaning that the singleton must never have transient stuff injected.

I suggest you register the state that you need to share between handlers in a dedicated component, and then you let a reference to that be injected in your - transient! 😁 - handlers.

I hope it makes sense πŸ˜„