如何在ServiceStack.net中使用Funq注册多个IDbConnectionFactory实例

Jef*_*ell 18 c# ioc-container inversion-of-control servicestack funq

您将如何在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));                
Run Code Online (Sandbox Code Playgroud)

这两个似乎都注入了谦逊的海鲂.

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

public IDbConnectionFactory DbFactory { get; set; }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它似乎给了我第一个注册.如何访问服务端的特定访问权限?希望这会让它更加清晰.

这是ServiceStack.Examples的完整示例,仅使用1个IDbConnectionFactory: Movies Rest

Ste*_*ven 14

我上面的问题仍然有效,但无论如何,以下内容可能会对您有所帮助.

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>());
Run Code Online (Sandbox Code Playgroud)

当然你也可以使用命名注册,如下所示:

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>());
Run Code Online (Sandbox Code Playgroud)

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

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

interface IYellowDbConnectionFactory : IDbConnectionFactory
{
}

interface IPurpleDbConnectionFactory : IDbConnectionFactory
{
}
Run Code Online (Sandbox Code Playgroud)

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

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

class PurpleDbConnectionFactory : OrmLiteConnectionFactory,
    IPurpleDbConnectionFactory 
{
    public YellowDbConnectionFactory(string s) : base(s){}
}
Run Code Online (Sandbox Code Playgroud)

现在,您应该更改服务的定义以使用特定的界面,而不是使用IDbConnectionFactory:

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

    public MovieService(IYellowDbConnectionFactory factory)
    {
        this.dbFactory = factory;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此类现在使用构造函数注入而不是属性注入.您可以使用属性注入来实现此功能,但通常最好使用构造函数注入.这是一个关于它的SO问题.

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

container.Register<MovieService>(c =>
    new MovieService(
        c.Resolve<IYellowDbConnectionFactory>());
Run Code Online (Sandbox Code Playgroud)

这两个新的接口和两个类并改变了MovieService并没有赢得你很多,因为Funq不支持自动布线.你将成为手动连接所有东西的人.然而,当你切换到一个框架,它支持自动布线,这样的设计允许容器没有问题注入合适的依赖关系,因为没有什么注入讨论.

  • 注意:ServiceStack确实支持使用Funq.Container进行自动连接 - 请参阅我的回答. (5认同)

myt*_*thz 11

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

container.RegisterAutoWired<T>();
container.RegisterAutoWiredAs<T,TAs>();
container.RegisterAs<T,TAs>();
Run Code Online (Sandbox Code Playgroud)

所以在Steven的例子中你也可以这样做:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>();
Run Code Online (Sandbox Code Playgroud)

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

  • Funq框架似乎已经被遗弃了很长时间.为什么不切换到Simple Injector作为ServiceStack的默认IoC框架?由于ServiceStack似乎是一个高性能框架,因此Simple Injector非常适合,因为它是该领域中速度最快的IoC框架.我认为ServiceStack非常好,顺便说一下. (2认同)
  • 回应我们对Funq的选择:Funq是一个完整的图书馆,完全按照它的目的去做.它是一个优雅的书面和富有表现力的库的例子,它提供90%的功能,只占其他重型IOC代码库的一小部分.我们正在维护和增强我们自己的嵌入式端口,并在需要时添加功能.如果有什么我们想要的东西丢失了,我们自己添加了它.邀请其他贡献者也这样做. (2认同)