dimanche 24 janvier 2021

Transient and Scoped services consuming a singleton data source

I am trying to learn dependency inversion and IOC. In the process, I have hit a wall.

This is what I understand about DI principle -> high-level classes are based on abstractions and not implementations.

All good.

So keeping the above in mind. I have the following example.

public interface IServiceA
{
   public void DoSomething();
}

public class ServiceA : IServiceAInterface
{
   IDataInterface dataSource;
   DataSourceType data;

   // omitted config injectino for brevity
   public ServiceA(IDataInterface _data)
   {
            dataSource = _dataSource;
            var dataSourceName = config.GetValue<string>("DataSourceName"); 
            data = dataSource.GetDataSource(dataSourceName);
   }

   public void doSomething()
   {
      data.doSomething();
   }
}
public interface IDataInterface
{
    public DataSourceType getDataSource(string ds);
}

public class DataAccessService : IDataInterface
{
        public DataSourceType GetDataSource(string dataSource)
        {
            if (dataSource == "InApp")
            {
                var source = new DataSourceType();
                return source;
            }
            else
            {
                return null;
            }
        }
}

The above is a service class which needs data to perform tasks which it gets from DataAccessService.

Now I am using an application class/model for persistence throughout the app lifetime. Therefore I have registered it as a singleton.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ---
    services.AddSingelton<IDataInterface,DataAccessService>();
    service.AddScoped<IServieAInterface,ServiceA>();
    ---
}

This does not work.

I hypothesize it is because, the parent service (service A) has a lesser lifetime than the child service (DataAccessService).

I have understood through this that service A is responsible for instantiation of the object.

However, I expected the IOC container to instantiate only one DataAccessService object and inject it to all services that need this.

Not sure why my assumption is wrong.

Based on the above hypothesis I tried the following:

public interface IDataInterface
{
}

public class DataAccessService : IDataInterface
{
    public DataSourceType dataSource;

    public DataAccessService(string ds)
    {
        if (ds == "InApp")
        {
            this.dataSource = new DataSourceType();
        }
        else
        {
            this.dataSource = null;
        }
    }
}

public class ServiceA: DataAccessService,IServceAInterface
{
    DatSourceTye data;
  
    public ServiceA():base("InApp")
    {
        config = _config;
        data = dataSource;
    }

    public void doSomething()
    {
      data.doSomething();
    }
}

Startup.cs

// Hoping to pass parameter through startup
services.AddSingleton<IDataInterface>(x =>
            ActivatorUtilities.CreateInstance<DataAccessService>(x, "InApp")
        );
service.AddScoped<IServieAInterface,ServiceA>();

I hoped the above would work, as here the DataAccessService is responsible for initialization.

But still a new DataAccessService object is created for every class.

I think, I have messed up my understanding about how the life times work. need help on this.

Also, what I am trying to achieve is a singleton data source on which different services act on throughout the application lifetime.

Transient and scoped services consuming a singleton data source. I think this should be possible

Is there something bad in terms of design in what I am trying to achieve?

Aucun commentaire:

Enregistrer un commentaire