Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am new to the DI patterns with .NETCore, and I am having trouble getting my connection strings to my DAL.

I followed the advice given in this thread via the accepted answer, and subsequent comments.

This is my base class

public class BaseRepository : IRepository<IDataModel>
{
    private readonly IConfiguration config;

    public BaseRepository(IConfiguration config)
    {
        this.config = config;
    }

    public string GetSQLConnectionString()
    {
        return config["Data:DefaultConnetion:ConnectionString"];
    }

This is a snippet of a repository class inheriting the base class

public class PrivacyLevelRepository : BaseRepository, IRepository<PrivacyLevelDM>
{
    public PrivacyLevelRepository(IConfiguration config) : base(config) { }
    public void Add(PrivacyLevelDM dataModel)
    {
         ...
    }
}

This is in my startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();
        services.AddScoped<IRepository<IDataModel>>(c => new BaseRepository(Configuration));
    }

However, In my service layer, the instantiation of the repository class is still asking for the (IConfiguration config) to be passed as a parameter.

 PrivacyLevelRepository repo = new PrivacyLevelRepository();

How do I get the IConfiguration loaded directly to my DAL, without having to pass it from Controller > BLL > DAL. This seems extremely inefficient, and incorrect. As the DAL should be determining the connection for an object, not the controller or service layer. They should be agnostic of the datasource, no?

I figure this is something simple, that I am just not seeing within the DI/IoC paradigm, but I cannot figure it out.

Edit: I am not using Entity Framework, but a custom Data layer.

Thanx for any help.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
348 views
Welcome To Ask or Share your Answers For Others

1 Answer

You could follow the options pattern with the configuration framework. This allows you to define a custom type that hold your configuration settings (statically typed) while being restricted to only your actual relevant configuration.

You can use it like this:

public void ConfigureServices(IServiceCollection services)
{
    // register the `Data:DefaultConnection` configuration section as
    // a configuration for the `DatabaseOptions` type
    services.Configure<DatabaseOptions>(Configuration.GetSection("Data:DefaultConnection"));

    // register your database repository
    // note that we don’t use a custom factory where we create the object ourselves
    services.AddScoped<IRepository<IDataModel>, BaseRepository>();
}

This assumes a type DatabaseOptions like this:

public class DatabaseOptions
{
    public string ConnectionString { get; set; }
}

Then, you can just have the DatabaseOptions injected into your BaseRepository:

public class BaseRepository
{
    private readonly DatabaseOptions _options;

    public BaseRepository(IOptions<DatabaseOptions> databaseOptions)
    {
         _options = databaseOptions.Value;
    }
}

Of course, if you have subtypes of that BaseRepository, you need to register those as well and pass the options to the base class:

// register the repository as well in the `ConfigureServices` method
services.AddScoped<PrivacyLevelRepository>();
public class PrivacyLevelRepository : BaseRepository, IRepository<PrivacyLevelDM>
{
    public PrivacyLevelRepository(IOptions<DatabaseOptions> databaseOptions)
        : base(databaseOptions)
    { }
}

I am instantiating and using the repo like I always have. I am not sure how to use a class that I don't instantiate. How do i let this object know it depends on the PrivacyLevelRepository?

PrivacyLevelRepository repo = new PrivacyLevelRepository();
returnValue = repo.GetAllByDomainID(DomainID).ToList();
return returnValue;

You do not appear to understand the idea behind dependency injection yet. Dependency injection with its underlying principle Inversion of Control is simply said about avoiding the use of new to create objects. Instead of actively depending on an implementation (in your example the PrivacyLevelRepository), you are giving up the responsibility and just depend on the outer system to provide you with the dependencies you need.

So instead of creating a new PrivacyLevelRepository, you inject an instance that is created by something somewhere else. That looses coupling on the implementation of your dependency. A very practical example of this is how PrivacyLevelRepository depends on IOptions<DatabaseOptions>. You, as a consumer of that repository, should not need to care to know how to get such an object to be able to create the repository instance. You shouldn’t even need to know how to create a repository instance in the first place.

So your consumer of PrivacyLevelRepository should follow the same idea as the repository itself: The repository does not know how to get those database options; it just depends on the constructing entity to pass such an object on. And your consumer, I assume a controller, should do the same:

public class MyController
{
    private readonly PrivacyLevelRepository _privacyLevelRepository;

    public MyController(PrivacyLevelRepository privacyLevelRepository)
    {
         // instead of *creating* a repository, we just expect to get one
         _privacyLevelRepository = privacyLevelRepository;
    }

    public IActionResult SomeRoute()
    {
         var domainId = "whatever";
         var data = _privacyLevelRepository.GetAllByDomainID(domainId).ToList();
         return View(data);
    }
}

Of course, something has to create the dependencies at some point. But if you embrace dependency injection completely—which ASP.NET Core not only makes very easy but also actively requires you to do so in order to work completely—then you don’t need to care about that part. You just register the types in the ConfigureServices method and then expect the dependencies to be fulfilled where you need them.

For more information, you should definitely check out the dependency injection chapter of the documentation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...