简体   繁体   中英

Dependency Injection With Interface but Constructor Needs String Parameter

I have a repository class that has a constructor with string parameter argument. It is a connection string. I created an interface for it and I'm using Unity in my UI project.

My question is, how do I set this up the 'right' way so that Unity will know how to properly construct my class in order to inject it when instantiating my controller?

I currently 'worked around' this by using a parameterless constructor for my repository but feel like this is a cop out.

Here is my repository constructor I want to use...

    public CobraLettersRepository(string dbConnectionString)
    {
        _connString = dbConnectionString ?? throw new ArgumentNullException(dbConnectionString);

        dbConnection = new SqlConnection(_connString);
        dbConnection.Open();
    }

I created ICobraLettersRepository and want to inject it into my controller constructor.

    public CobraLetterController(ICobraLetterRepository cobraLetterRepository)
    {
        if (cobraLetterRepository == null)
            throw new ArgumentNullException(cobraLetterRepository);

        _cobraLetterRepo = cobraLetterRepository;
    }

When I try this, the code compiles but I get runtime errors whenever I attempt to navigate to a part of my app where those controller methods are called.

I would say to encapsulate the Connection String inside a configuration object and put the get of the connection string inside the constructor of that configuration object. Then just register your configuration object as other class.

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

    public ProjectConfiguration()
    {
        ConnectionString = //Get the configuration from , i.e: ConfigurationManager
    }

}

And then, inject it :

public CobraLettersRepository(ProjectConfiguration configuration)
{
    if(configuration == null){
        throw new ArgumentNullException(configuration);
    }
    _connString = configuration.ConnectionString;

    dbConnection = new SqlConnection(_connString);
    dbConnection.Open();
}

With that you can always isolate the config from the DI container and leave the injection as simple as you can. Also, you can get the config from your config files (one per environment).

EDIT: Also check your repository constructor logic, maybe you don't want to Open the connection on the constructor. Is better to make a using statement on your class methods like :

using(SqlConnection connection = new SqlConnection(_injectedConfiguration.ConnectionString)){
    connection.Open();
    //Make your stuff here
}

With the using you ensure that the connection will be correctly disposed.

Note that with the configuration object approach you can just store the configuration object in a private readonly variable and use it whatever you need.

During registration use an InjectionConstructor to pass the connection string name. You need to remove all constructors except one that expects a string argument.

container.RegisterType<ICobraLetterRepository,CobraLettersRepository>(new InjectionConstructor("connectionstringname"));

Please note that it will lead to problems somewhere/sometime. You need to change the logic to create the database connection (you may refer to Breaking SOLID Principles in multiple implementation of an Interface or Resolve named registration dependency in Unity with runtime parameter ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM