How can I specify an argument for the Repository's constructor from the Controller?

I had a good answer for my question here, but I'm not sure if I can apply that answer to my project, because I would apparently need to use code something like this in my controllers:

return DBConnectionStrings[DBSpecifier].Get(ID, CountToFetch);

...(where DBConnectionStrings is a Dictionary) instead of:

return deptsRepository.Get(ID, CountToFetch);

The real problem/challenge is that I need my Repositorys' constructors to be able to accept an arg so as to change the DB connection string accordingly. Those constructors could then use the Dictionary suggested in the earlier post, so that instead of starting like this:

public DuckbillRepository()
{
    using (var conn = new OleDbConnection(
        @"Provider=Microsoft.Jet.OLEDB.4.0;User ID=NRBQ;Password=NRBQRotPS;Data 
           Source=C:\Platypus\DATA\PlatypusFlipper03.MDB;Jet OLEDB:System 
           database=C:\Platypus\Data\duckbill.mdw"))
    {

...it would be something like this:

public DuckbillRepository(string DBToUse)
{
    using (var conn = new OleDbConnection(
        string.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;User 
          ID=NRBQ;Password=NRBQRotPS;Data Source=C:\Platypus\DATA\{0}.MDB;Jet 
          OLEDB:System database=C:\Platypus\Data\duckbill.mdw", DBToUse))
    {

But how can I, from the Controller, specify an arg for the Repository's constructor (which is what is used to populate the data store that the Repository's methods then query)? Currently, the typical Controller looks like this:

static readonly IDuckbillRepository duckbillsRepository = new DuckbillRepository();

public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(int ID, int CountToFetch)
{
    return duckbillsRepository.Get(ID, CountToFetch);
}

The best idea/closest I can come up with at present would be that I need something like this instead:

public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(string DBInstance, int ID, int CountToFetch)
{
    IDuckbillRepository duckbillsRepository = new DuckbillRepository(DBInstance);
    return duckbillsRepository.Get(ID, CountToFetch);
}

Am I on the right track, or barking up the wrong tree?

Upvotes: 2

Views: 168

Answers (2)

Ilya Palkin
Ilya Palkin

Reputation: 15767

I you want to avoid usage of any IoC you have the following options.

  1. If user can specify dbInstance as method parameter only then it is enough to have several constructors for DuckbillRepository type and simply invoke appropriate one.

    public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(
        string dbInstance, 
        int id, 
        int countToFetch)
    {
        var duckbillsRepository = new DuckbillRepository(dbInstance);
        return duckbillsRepository.Get(id, countToFetch);
    }
    
  2. If it is possible to get dbInstance in the DuckbillItemsController's constructor then I would implement duckbillRepository field and initialise it in the constructor.

    /// <summary>
    /// Dependency Injection friendly controller.
    /// </summary>
    public class DuckbillItemsController : ControllerBase
    {
        public readonly DuckbillRepository duckbillRepository;
    
        public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(
            int id, 
            int countToFetch)
        {
            return duckbillRepository.Get(id, countToFetch);
        }
    
        /// <summary>
        ///     <see cref="HttpContext.Current"/> can be a source 
        ///     of 'dbInstance' variable.
        /// </summary>
        public DuckbillItemsController()
            : this(HttpContext.Current.Request["dbInstance"])
        {
        }
    
        public DuckbillItemsController(string dbInstance)
            : this(new DuckbillRepository(dbInstance))
        {
        }
    
        public DuckbillItemsController(DuckbillRepository duckbillRepository)
        {
            this.duckbillRepository = duckbillRepository;
        }
    }
    

If it is OK to use IoC then you can read about Passing Arguments in Castle Windsor IoC.

var repository = 
    container.Resolve<DuckbillRepository>(new Arguments(new { dbInstance }));

This approach is useful for parameters that are available in the composition root, like your Program.Main method. While it may look simple at the beginning, and is in fact often used by people new to Windsor, it's applicability is generally quite limited, and the other two ways are used much more often.

  1. Registration time - DependsOn and DynamicParameters
  2. Resolution time - typed factories

Upvotes: 2

I have devised a plan to make this work, but consider it kludgy and am looking for either verification ("yeah, it's ugly, but that's about all you can do") or a better idea.

In the controller, change this:

static readonly IDuckbillRepository deptsRepository = new DuckbillRepository();

...to this:

static readonly IDuckbillRepository deptsRepository = new DuckbillRepository(string siteVal);

In the Repository, change the constructor from this:

public DuckbillRepository()
{
    using (var conn = new OleDbConnection(
        @"Provider=Microsoft.ACE.OLEDB.12.0;User ID=NRBQ;Password=NRBQ;Data Source=C:\PlatypusFin\DATA\PlatypusDAT03.MDB;Jet OLEDB:System database=C:\PlatypusFin\Data\nrotps.mdw"))
    {
        using (var cmd = conn.CreateCommand())
        {
            . . .

...to this:

public DuckbillRepository(string siteVal)
{
    string connStr = string.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;User ID=NRBQ;Password=NRBQ;Data Source=C:\PlatypusFin\DATA\{0}.MDB;Jet OLEDB:System database=C:\PlatypusFin\Data\nrotps.mdw", siteVal);
    using (var conn = new OleDbConnection(connStr))
    {
        using (var cmd = conn.CreateCommand())
        {
             . . .

Upvotes: 0

Related Questions