How to share the same instance with multiple interfaces in scoped service lifetime
Asked Answered
B

2

5

Here is an example similar to the one on this page.

public interface IOperation
{
  string OperationId { get; }
}

public interface IScopedOperation1 : IOperation { }

public interface IScopedOperation2 : IOperation { }

public class DefaultOperation : IScopedOperation1, IScopedOperation2
{
   public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}

public class OperationLogger
{
  private readonly IScopedOperation1 _scopedOperation1;
  private readonly IScopedOperation2 _scopedOperation2;

  public OperationLogger(
      IScopedOperation1 op1, IScopedOperation2 op2) =>
      (_scopedOperation1, _scopedOperation2) = (op1, op2);

  public void LogOperations()
  {
     Console.WriteLine($"Operation1: [ {_scopedOperation1.OperationId} ]");
     Console.WriteLine($"Operation2: [ {_scopedOperation2.OperationId} ]");
  }
}

And then if registered and called like this

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((_, services) =>
        services
         .AddScoped<IScopedOperation1, DefaultOperation>()
         .AddScoped<IScopedOperation2, DefaultOperation>()
         .AddTransient<OperationLogger>())
    .Build();

host.Services.GetService<OperationLogger>().LogOperations();

Once LogOperations are called then OperationId is different for each injected instance.

Is there a way to share the same instance in the scoped service lifetime?

Bitstock answered 2/11, 2022 at 18:32 Comment(0)
V
12

First, register DefaultOperation as itself with scoped lifetime.

AddScoped<DefaultOperation>();

This way you will always have one object per scope. Then, register interfaces to return that object.

services.AddScoped<IScopedOperation1>(sp => sp.GetService<DefaultOperation>());
services.AddScoped<IScopedOperation2>(sp => sp.GetService<DefaultOperation>());

Here, sp is of type IServiceProvider, through which you can call this very container and get any service.

Vedavedalia answered 2/11, 2022 at 18:56 Comment(1)
Is the cast to interface required?Carrick
R
1

Since there's a guaranty that the service exists, you can use the functions with non-nullable return and get rid of a warning:

services
    .AddScoped<DefaultOperation>()
    .AddScoped<IScopedOperation1>(_ => _.GetRequiredService<DefaultOperation>())
    .AddScoped<IScopedOperation2>(_ => _.GetRequiredService<DefaultOperation>())
Ridicule answered 6/5 at 7:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.