2

In ASP.NET 5, I have an IRepository interface that I used to access some databases, like this:

public interface IRepository {
    IQueryable<T> QueryItems(string sql);
}

public class Repository : IRepository {

    private readonly string ConnectionString;

    public Repository(string connStr) {
        // Save the injected connection string
        this.ConnectionString = connStr;
    }

    public IQueryable<T> QueryItems(string sql) {
        // Implementation ignored here
    }
}

In my Startup.cs class, I am registering the IoC/DI like this:

services.AddTransient<IRepository>(s => new Repository("DUMMY_CONNSTR"));

That all works fine if I only have one connection string. However, how can I register and subsequently inject the correct IRepository if I use the Repository to connect to 2+ different databases with different connection strings?

services.AddTransient<IRepository>(s => new Repository("DUMMY_CONNSTR"));
services.AddTransient<IRepository>(s => new Repository("DIFFERENT_CONNSTR"));

In older IoC/DI systems, I would have use "named" implementations that could be resolved with something like a [Dependency("DUMMY")] attribute on the constructor parameter.

Any help would be appreciated.

hpopiolkiewicz
  • 3,281
  • 4
  • 24
  • 36
cwiederspan
  • 95
  • 1
  • 7

2 Answers2

1

There are a few approach that you can take one is to inject a factory and base on the specific criteria you can produce a repository, the other approach is use a Dispatcher that also produce the repository base on the criteria, below is a question that I ask with the same problem. The question below have both approach but they were codding a beta version of .net core

See this question for reference and code

Community
  • 1
  • 1
Son_of_Sam
  • 1,913
  • 2
  • 22
  • 37
  • Thanks, wish I'd have seen question yesterday. I have used the factory approach in the past, and it's probably the best solution for my needs. For better or worse, I was hoping for a lazier solution that wouldn't require me to make a decision (somewhere) as to which repository I needed in my controllers. I currently settled on putting a different "marker" interface on my repository so that I could resolve it uniquely depending on my needs, but that only worked because I owned the repository code - wouldn't have been able to do that if the repository was external. – cwiederspan Jan 27 '16 at 21:13
  • under that question there is dispatcher example, where you make the deccicion in the startup.cs take a look. – Son_of_Sam Jan 27 '16 at 22:02
0

You can substitute StructureMap or Autofac for the default DI container (see my blog post for detailed instructions). Both support "named" interface registration (StructureMap named instances and Autofac named and keyed services).

Additionally, if you target dnx451, you can use Autofac's WithKey attribute. Using the Visual Studio sample project from the blog post, add the following dependency in project.json:

"frameworks": {
  "dnx451": {
    "dependencies": {
      "Autofac.Extras.AttributeMetadata": "4.0.0"
    }
  }
},

Given a test class with the following constructor:

public MyClass([WithKey("logging")] IRepository repository)
{
    Repository = repository;
}

you would register everything in ConfigureServices (note the use of WithAttributeFilter():

containerBuilder.Register(c => new Repository("DEFAULT_CONNSTR")).Keyed<IRepository>("default");
containerBuilder.Register(c => new Repository("LOGGING_CONNSTR")).Keyed<IRepository>("logging");

containerBuilder.RegisterType<MyClass>().WithAttributeFilter();
Jeff Ogata
  • 56,645
  • 19
  • 114
  • 127