Home > Blockchain >  Minmal API DI reconstructs dependencies even when registered as singleton
Minmal API DI reconstructs dependencies even when registered as singleton

Time:10-08

Started working on a windows background service in .net that will host a restful service. As I worked on it, it seemed like Minimal APIs were a good fit (it was one of the things I was able to get a working prototype with, I couldn't get other stuff to work). However, I'm not sure if I'm misunderstanding something here. When I inspect one of my injected services, I'm noticing that it's being reconstructed each time the endpoint is hit. I didn't think that would happen if I register my services as singletons. Something tells me that due to the nature of Minimal API, there is no way around that. Am I missing something?

I'm using MessagePipe for .net. SquareService implements IAsyncRequestHandler<LocationByNameRequest, LocationResponse>

The registration.

builder.Services.AddMessagePipe();
builder.Services.AddSingleton<SquareService>();

The injection.

app.MapPut("/pos",
 async (POS station, 
IAsyncRequestHandler<LocationByNameRequest, LocationResponse> handler) => { ...});

I made sure that Visual Studio wasn't just randomly ouputing log messages, so I set up a GUID in the constructor to verify if the instances might be different (they are). How else would I host an api in a windows service? Been having problems integrating this, and I think it's because I'm not getting the same references as I was expecting. Any guidance would be greatly appreciated.

CodePudding user response:

That has nothing to do with Minimal APIs per se. First of all builder.Services.AddSingleton<SquareService>(); will register just SquareService, not the interfaces it implements, if you resolve SquareService in the handler you will get exactly the same instance every time:

app.MapPut("/pos", async (POS station, SquareService handler) => ...);

It seems that MessagePipe has it's own custom DI/Lifetime handling. For publishers/subscribers you manipulate the registration type individually by using corresponding interfaces - see this part of the doc:

I(Async)Publisher(Subscriber)'s lifetime is belonging MessagePipeOptions.InstanceLifetime. However if declare with ISingletonPublisher<TMessage>/ISingletonSubscriber<TKey, TMessage>, ISingletonAsyncPublisher<TMessage>/ISingletonAsyncSubscriber<TKey, TMessage> then used singleton lifetime. Also IScopedPublisher<TMessage>/IScopedSubscriber<TKey, TMessage>, IScopedAsyncPublisher<TMessage>/IScopedAsyncSubscriber<TKey, TMessage> uses scoped lifetime.

But for handlers the only option is to set it globally for all the handlers via MessagePipeOptions (docs):

Configure IRequestHandler/IAsyncRequestHandler's lifetime of DI container. You can choose Singleton or Scoped or Transient. Default is Scoped.

services.AddMessagePipe(options => options.RequestHandlerLifetime = InstanceLifetime.Singleton);
  • Related