Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to register a named instance with Simple Injector

I'm developing a WinForm application and I'm using Repository Pattern , I'm using Servicestack OrmLite for data access and Simple Injector for IoC.

In my program.cs I have 2 register 2 different OrmLiteConnectionFactory but currently I'm not able to since I can't register named... with FunQ I can do this with

container.Register<IDbConnectionFactory>("db1", _ => new OrmLiteConnectionFactory(
    ConfigurationManager.ConnectionStrings["db1"].ConnectionString, 
    SqlServerDialect.Provider));
container.Register<IDbConnectionFactory>("db2", _ => new OrmLiteConnectionFactory(
    ConfigurationManager.ConnectionStrings["db2"].ConnectionString, 
    SqlServerDialect.Provider));

here is mine program.cs Bootstrap method

private static void Bootstrap()
{
    // Create the container as usual.
    Container = new Container();

    string conn1 = ConfigurationManager.ConnectionStrings["dbconn1"].ConnectionString;
    string conn2 = ConfigurationManager.ConnectionStrings["dbconn2"].ConnectionString;

    OrmLiteConnectionFactory connectionFactory = new OrmLiteConnectionFactory(conn1,
        ServiceStack.OrmLite.SqlServer.SqlServerOrmLiteDialectProvider.Instance); 
    Container.RegisterSingle<OrmLiteConnectionFactory>(connectionFactory1);

    OrmLiteConnectionFactory connectionFactory2 = new OrmLiteConnectionFactory(conn2,
        ServiceStack.OrmLite.SqlServer.SqlServerOrmLiteDialectProvider.Instance); 

    // how do I register this one without a name?
    Container.RegisterSingle<OrmLiteConnectionFactory>(connectionFactory2);

    Container.Register<MainForm>();
}

Thanks in advance

like image 571
advapi Avatar asked Dec 19 '14 08:12

advapi


1 Answers

Since you have have two different databases with each a different schema, the different OrmLiteConnectionFactory aren't interchangable. This means that if you swap them around, your system will stop working. That's an indication that you are breaking the Liskov Substitution Principle. So the general solution in that case is to give each factory its own interface and let each repository depend on that particular interface. That allows you to register them uniquely and let the container resolve the object graph without doubt.

If giving each factory its own abstraction is not an option, or convenient, another option is to register your repositories without auto-wiring. By registering your repository with a delegate, you are completely in control over what to inject into your repository. For instance:

container.Register<IOrderRepository>(() => new SqlOrderRepo(connectionFactory1));

container.Register<IUserRepository>(() => new SqlUserRepo(
    connectionFactory2,
    container.GetInstance<ILogger>()));

A third option is to use context based injection, were you do the following:

var f1 = Lifestyle.Singleton.CreateRegistration<IDbConnectionFactory>(
    () => new OrmLiteConnectionFactory(
            conn1,
            ServiceStack.OrmLite.SqlServer.SqlServerOrmLiteDialectProvider.Instance), 
        container);

var f2 = Lifestyle.Singleton.CreateRegistration<IDbConnectionFactory>(
    () => new OrmLiteConnectionFactory(
            conn2,
            ServiceStack.OrmLite.SqlServer.SqlServerOrmLiteDialectProvider.Instance), 
        container);

container.RegisterConditional(typeof(IDbConnectionFactory), f1, InjectedInto<SqlOrderRepo>);
container.RegisterConditional(typeof(IDbConnectionFactory), f2, InjectedInto<SqlUserRepo>);

// Helper method.
static bool InjectedInto<T>(PredicateContext c) =>
    c.Consumer.ImplementationType == typeof(T);

Out of the box Simple Injector does not support registering keyed registrations, but there are several ways to do this as explained on this page. That page also explains why there is no built-in support for this. This is a deliberate design decision.

like image 192
Steven Avatar answered Oct 24 '22 13:10

Steven