A service which using EventStoreClient - should I register it as singleton or transient

I am doing a similar service like “AggregateRepository” on this site (but I use gRPC instead of TCP):

The service use EventStoreClient, load events from EventStore and save events to EventStore.

I wonder which Microsoft dependency injection lifetime I should use. EventStoreClient is registered as Singleton so I thought the service should also be registered as Singleton.

But on the website above “AggregateRepository” is registered as Transient. So now I don’t know.

Here are Microsoft dependency injection lifetimes:

  1. AddTransient
    Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.

  2. AddScoped
    Scoped lifetime services are created once per request.

  3. AddSingleton
    Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the same instance.

Which should I choose?

There is an extension method in the nuget package that registers the client as a singleton

source code

Yes, I have it:

services.AddEventStoreClient("connection string");

But how to register a service which uses EventStoreClient?

services.AddSingleton<AggregateRepository>();
// or:
services.AddTransient<AggregateRepository>();

???
I mean this service:

public class AggregateRepository
{
        private readonly EventStoreClient _eventStoreClient;

        public AggregateRepository(EventStoreClient eventStoreClient)
        {
            _eventStoreClient = eventStoreClient;
        }

        public async Task SaveAsync<T>(T aggregate) where T : Aggregate, new()
        {
		    //....
            await _eventStore.AppendToStreamAsync(streamName, StreamState.Any, events);
        }

        public async Task<T> LoadAsync<T>(Guid aggregateId) where T : Aggregate, new()
        {
		    //....
			
            var readStreamResult = _eventStoreClient.ReadStreamAsync(
                    Direction.Forwards,
                    streamName,
                    StreamPosition.Start);
					
			//....
        }
}

My 2 cents.

If your only “state” within that service (the aggregate in this case) is your singleton instance of event store client, then it doesn’t matter how you register it because its event store client will always be the same thread safe instance.

There is basically zero cost in registering aggregate as transient and instantiating it when needed unless you have a good reason to always keep the instance in memory.

If you have another service B in that aggregate that is transient, then, if your aggregate is registered as single instance it will prevent new instances of the service B to be injected, as your aggregate will always exist with the first instance of B that was injected the first time.

That’s why by default I go with transient unless it’s a clear benefit/need to use single instance.

Indeed .
EventStore’s client is thread safe and meant to be shared so can be registered as singleton

The lifetime in DI of objects needed by your application is entirely up to you and is heavily dependent on the DI container you use.
Microsoft has some guidelines here

Now if all you do is using Transient for your repository, just do a new Repository(eventStoreClient) and pass the client as the dependency. your registrations will be way simpler to manage.

OK, thank you - my AggregateRepository is dependend only on EventStoreClient so I will register AggregateRepository as Transient.