19

您将如何在 Funq 中注册不同的 IDbConnectionFactory 实例,然后在您的服务中直接访问它们?命名实例会以某种方式在这里发挥作用吗?

当跨服务使用不同的数据库时,这是最好的方法吗?

谢谢!

编辑:

一个例子 ;)。我可能会离开这里,因为我对 IoC 还很陌生,但是比如说我有 2 个要注入的独立数据库连接。在 ServiceStack 中,这是在 Global.asax 中完成的。

container.Register<IDbConnectionFactory>(c =>
            new OrmLiteConnectionFactory(@"Connection String 1", SqlServerOrmLiteDialectProvider.Instance));                                             

container.Register<IDbConnectionFactory>(c =>
            new OrmLiteConnectionFactory(@"Connection String 2", SqlServerOrmLiteDialectProvider.Instance));                

这两个似乎都被注入了honky dory。

然后通过以下方式在服务端自动访问这些:

public IDbConnectionFactory DbFactory { get; set; }

在这种情况下,它似乎是给我第一个注册的。如何在服务端访问特定的?希望这使它更清楚一点。

这是来自 ServiceStack.Examples 的完整示例,它仅使用 1 个 IDbConnectionFactory: 电影休息

4

5 回答 5

15

我上面的问题仍然有效,但以下内容可能对您有所帮助。

Funq 不支持自动构造函数注入(也称为自动连接),您必须通过构造Func<T>lambda 表达式手动完成此操作。因为您已经在手动进行构造函数注入,所以很容易选择IDbConnectionFactory要注入到服务中的内容。例子:

IDbConnectionFactory yellowDbConFactory =
    new YellowDbConnectionFactory();

IDbConnectionFactory blueDbConFactory =
    new BlueDbConnectionFactory();

IDbConnectionFactory purpleDbConFactory =
    new PurpleDbConnectionFactory();

container.Register<IService1>(c =>
    new Service1Impl(yellowDbConFactory,
        c.Resolve<IDep1>());

container.Register<IService2>(c =>
    new Service2Impl(blueDbConFactory);

container.Register<IService3>(c =>
    new Service3Impl(purpleDbConFactory, 
        c.Resolve<IDep2>());

当然你也可以使用命名注册,像这样:

container.Register<IDbConnectionFactory>("yellow",
    new YellowDbConnectionFactory());

container.Register<IDbConnectionFactory>("blue",
    new BlueDbConnectionFactory());

container.Register<IDbConnectionFactory>("purple",
    new PurpleDbConnectionFactory());

container.Register<IService1>(c =>
    new Service1Impl(
        c.Resolve<IDbConnectionFactory>("yellow"),
        c.Resolve<IDep1>());

container.Register<IService2>(c =>
    new Service2Impl(
        c.Resolve<IDbConnectionFactory>("blue"));

container.Register<IService3>(c =>
    new Service3Impl(
        c.Resolve<IDbConnectionFactory>("purple"), 
        c.Resolve<IDep2>());

由于缺乏对自动装配的支持,您最终会得到这些相当尴尬的注册,这很快就会导致您的作曲根维护噩梦,但这与您的问题无关;-)

您通常应该尽量避免在您的注册中出现歧义。在您的情况下,您有一个接口,它做两件事(连接到两个数据库)。除非两个数据库共享完全相同的模型,否则每个数据库都应该有自己的接口(如果两个实现不可互换,您将违反Liskov 替换原则):

interface IYellowDbConnectionFactory : IDbConnectionFactory
{
}

interface IPurpleDbConnectionFactory : IDbConnectionFactory
{
}

由于 ServiceStack 的工作方式,您可能需要为每个实现一个实现:

class YellowDbConnectionFactory : OrmLiteConnectionFactory,
    IYellowDbConnectionFactory
{
    public YellowDbConnectionFactory(string s) : base(s){}
}

class PurpleDbConnectionFactory : OrmLiteConnectionFactory,
    IPurpleDbConnectionFactory 
{
    public YellowDbConnectionFactory(string s) : base(s){}
}

现在您应该更改服务的定义以使用特定接口而不是使用IDbConnectionFactory

public class MovieService : RestServiceBase<Movie>
{
    private readonly IYellowDbConnectionFactory dbFactory;

    public MovieService(IYellowDbConnectionFactory factory)
    {
        this.dbFactory = factory;
    }
}

请注意,此类现在使用构造函数注入而不是属性注入。你可以让它与属性注入一起工作,但通常最好使用构造函数注入。这是一个关于它的问题

使用 Funq,您的配置将如下所示:

container.Register<MovieService>(c =>
    new MovieService(
        c.Resolve<IYellowDbConnectionFactory>());

这两个新接口和两个类并MovieService没有给你带来很多好处,因为 Funq 不支持自动装配。您将成为手动将所有内容连接在一起的人。但是,当您切换到支持自动装配的框架时这种设计允许容器毫无问题地注入正确的依赖项,因为没有关于注入什么的讨论。

于 2012-01-07T00:49:28.570 回答
11

虽然 Funq 不支持自动布线,但它的ServiceStack实现支持。最新版本的 ServiceStack 包括 Funq.Container 重载:

container.RegisterAutoWired<T>();
container.RegisterAutoWiredAs<T,TAs>();
container.RegisterAs<T,TAs>();

所以在史蒂文的例子中,你也可以这样做:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>();

它会自动为您注册依赖项。

于 2012-01-08T13:34:52.057 回答
3

以为我会在这里投入 2 美分,尽管我意识到这个问题已经很老了。我想从 ServiceStack 访问事务数据库和日志数据库,这就是我最终从 AppHostBase Configure() 方法完成它的方式:

            container.Register<IDbConnectionFactory>(
                c => {
                    OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings["MyTransactionalDB"].ConnectionString, MySqlDialect.Provider);
                    dbFactory.ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current);
                    dbFactory.RegisterConnection("LoggingDB", ConfigurationManager.ConnectionStrings["MyLoggingDB"].ConnectionString, MySqlDialect.Provider);

                    return dbFactory;
                });

默认情况下,从工厂打开连接时使用“MyTransactionalDB”,但我可以通过以下方式从服务显式访问日志记录数据库:

        using (var db = DbFactory.Open("LoggingDB"))
        {
            db.Save(...);
        }
于 2015-10-25T11:29:40.973 回答
1

尝试使用存储库模式而不是这个 IoC(这只会使事情变得不必要地复杂化)。上面的代码似乎不起作用。怀疑有什么变化。我仍然不清楚注册 IDbConnectionFactory 如何神奇地填充 IDbConnection 属性。希望对此进行一些解释。如果有人确实使用 ServiceStack IoC 容器来完成这项工作..那么我很想看看如何。更新 SS 文档将非常有益(我很乐意这样做)

于 2013-10-13T19:57:45.267 回答
1

您也可以使用字典

使用您的数据库键名创建一个枚举

public enum Database
    {
        Red,
        Blue
    }

在 Startup.cs 中,创建一个打开新 SqlConnection 的函数字典,然后将依赖字典注入为 Singleton

Dictionary<Database, Func<IDbConnection>> connectionFactory = new()
   {
      { Database.Red, () => new SqlConnection(Configuration.GetConnectionString("RedDatabase")) },
      { Database.Blue, () => new SqlConnection(Configuration.GetConnectionString("BlueDatabase")) }
   };
services.AddSingleton(connectionFactory);

在您可以像这样获得实例 od 对对象构造函数的依赖之后:

public class ObjectQueries
{
   private readonly IDbConnection _redConnection;
   private readonly IDbConnection _blueConnection;

   public ObjectQueries(Dictionary<Database, Func<IDbConnection>> connectionFactory)
   {
      _redConnection = connectionFactory[Database.Red]();
      _blueConnection = connectionFactory[Database.Blue]();
   }
}

它干净易读;)

于 2021-03-04T11:10:22.247 回答