SimpleInjector - 注册多个数据库连接

时间:2018-02-01 21:32:37

标签: c# dapper simple-injector ormlite-servicestack

我正在使用现有的WebApi,它使用SimpleInjector注册单个数据库连接。我需要建立一个端点来从不同的数据库获取信息,但我不知道如何注册新的连接。

这些是主db的现有注册:

_container.Register<IDataBaseSqlServerDapper>(
    () => new DataBaseSqlServerDapper(SqlServerDb.ConnectionString(),
    LogManager.GetLogger("")));

_container.RegisterWebApiRequest<IDbConnectionFactory>(
    () => new OrmLiteConnectionFactory(SqlServerDb.ConnectionString(),
    new SqlServerOrmLiteDialectProvider()));

_container.RegisterWebApiRequest(
    () => new PetaPoco.Database(Connection.SurveyEngine) {
        IsolationLevel = IsolationLevel.Snapshot
    });

所以我读了一下RegisterCollection方法,我尝试了以下内容:

_container.RegisterCollection<IDataBaseSqlServerDapper>(new[]
{
   new DataBaseSqlServerDapper(SqlServerDb.ConnectionString(), LogManager.GetLogger("")),
   new DataBaseSqlServerDapper(AdmbbDb.ConnectionString(), LogManager.GetLogger(""))
});

_container.RegisterCollection<IDbConnectionFactory>(new[]
{
    new OrmLiteConnectionFactory(
        SqlServerDb.ConnectionString(), 
        new SqlServerOrmLiteDialectProvider()),
    new OrmLiteConnectionFactory(
        AdmbbDb.ConnectionString(), 
        new SqlServerOrmLiteDialectProvider())
});

_container.RegisterCollection<PetaPoco.Database>(new[]
{
     new PetaPoco.Database(Connection.SurveyEngine) { 
        IsolationLevel = IsolationLevel.Snapshot },
     new PetaPoco.Database(Connection.Admbb) { 
        IsolationLevel = IsolationLevel.Snapshot }
});

SqlServerDb,AdmbbDd和Connection是包含连接字符串名称的类。

但是我收到了这个错误:

  

配置无效。为类型IDapperQueryFactory创建实例失败。 DapperQueryFactory类型的构造函数包含名称为&#39; dataBaseSqlServerDapper&#39;的参数。并键入未注册的IDataBaseSqlServerDapper。请确保已注册IDataBaseSqlServerDapper,或更改DapperQueryFactory的构造函数。但是,IEnumerable&lt; IDataBaseSqlServerDapper&gt;的注册;你的意思是依赖于IEnumerable&lt; IDataBaseSqlServerDapper&gt;?

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

在现有情况下,您指定可以使用类型IDataBaseSqlServerDapper进行注入,然后将其正确注入对象(在本例中为实现IDapperQueryFactory的类)。

在第二种情况下,您正在注册类型为IDataBaseSqlServerDapper服务。这意味着您的DI不知道如何解析单个IDataBaseSqlServerDapper,只知道它们的集合。

这意味着您必须更改构造函数以接受IEnumerable<IDataBaseSqlServerDapper>或注册非集合IDataBaseSqlServerDapper

他们的文档列出了一个很好的例子,说明如何同时使用Register和RegisterCollection使其工作(source)。

至于你的问题,你说:

  

我需要建立一个端点来从不同的数据库获取信息,但我不知道如何注册新连接。

如果您只是想改变数据的去向,那么您是否只能替换旧的现有处理程序?

如果您的目标是从多个数据源加载数据,那么您需要具有某种逻辑,允许您的代码确定应该使用哪个源来存储/加载数据。

simpleinjector文档中的示例为此类提供了良好的基础,不需要您重写使用注入IDataBaseSqlServerDapper的类。

答案 1 :(得分:0)

我的情况与此类似,但简单一些。我正在为遇到类似我的问题的任何人发布我的解决方案。

问题

我需要一种方法来使用以不同参数(连接字符串名称)初始化的单个具体类型(在我的情况下为NPoco.Database)的多个实例。由于SimpleInjector doc examples使用实现ILogger 的类都具有无参数的构造函数,因此我发现很难弄清楚如何使我的方案工作。

解决方案

我终于想出了一个简单的NPoco.Database子类,它需要连接到每个数据库,然后使用Container.RegisterConditional注册实例。由于RegisterConditional没有带构造函数的重载,因此我必须给这些子类中的每个无参数构造函数,这些构造函数使用适当的连接字符串名称调用了基础Database类。最后,一些使用者来自外部NuGet程序包(在我的组织内部),并且依赖于注入IDatabase而不是派生类型,因此我不能仅仅依靠注册派生类型并让SimpleInjector根据仅此而已。

代码

话虽如此,这是我的解决方法。

NPoco.Database的子类

public class FirstSubDatabase : Database
{
    public FirstSubDatabase()
        : base("FirstSubConnection") { }
}

public class SecondSubDatabase : Database
{
    public SecondSubDatabase()
        : base("SecondSubConnection") { }
}

注册

container.RegisterConditional<IDatabase, FirstSubDatabase>(
    Lifestyle.Scoped,
    c => c.Consumer.ImplementationType.FullName?.StartsWith(
        "external.lib.", StringComparison.OrdinalIgnoreCase) ?? false);

container.RegisterConditional<IDatabase, SecondSubDatabase>(
    Lifestyle.Scoped,
    c => c.Consumer.ImplementationType == typeof(LocalConsumerClass));

注意:“ external.lib”。只是外部NuGet包中所有内容的名称空间。这样可以避免将来的编辑者(包括我自己)不得不花时间弄清楚为什么要实例化对该包中的另一个服务的依赖。