Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
163 views
in Technique[技术] by (71.8m points)

c# - How to register multiple IDbConnectionFactory instances using Funq in ServiceStack.net

How would you go about registering diferent IDbConnectionFactory instances in Funq and then access them directly within your services? Do named instances somehow come into play here?

Is this the best approach to take when using different databases across services?

Thanks!

EDIT:

An example ;). I could be way off here because I'm pretty new to IoC, but say for example I have 2 separate database connections that I'd like to inject. In ServiceStack, this is done in the Global.asax.

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

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

Both of these seem to be injected honky dory.

These are then accessed automatically on the service end via something like this:

public IDbConnectionFactory DbFactory { get; set; }

In this case, it seems to be giving me the first one registered. How can I get access to a specific one on the service end? Hopefully that makes it a little more clear.

Here's a full fledged example from ServiceStack.Examples that only uses 1 IDbConnectionFactory: Movies Rest

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

My question above is still valid, but the following might help you anyway.

Funq does not support automatic constructor injection (a.k.a. auto wiring), and you will have to do this by hand by constructing Func<T> lambda expressions. Because you are already doing constructor injection by hand, it is easy to choose what IDbConnectionFactory you wish to inject into your services. Example:

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>());

Of course you can also used named registrations, like this:

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>());

Because of the lack of support for auto-wiring, you'll end up with these rather awkward registrations, and this will pretty soon result in a maintenance nightmare of your composition root, but that's unrelated to your question ;-)

You should usually try to prevent ambiguity in your registration. In your case you've got a single interface, that does two things (connects to two databases). Unless both database share the exact same model, each database deserves its own interface (if the two implementations are not interchangable, you'll be violating the Liskov substitution principle):

interface IYellowDbConnectionFactory : IDbConnectionFactory
{
}

interface IPurpleDbConnectionFactory : IDbConnectionFactory
{
}

Because of the way ServiceStack works, you probably need to implement an implementation for each:

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

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

Now you should change the definition of your services to use the specific interface instead of using the IDbConnectionFactory:

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

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

Note that this class now uses constructor injection instead of property injection. You can get this to work with property injection, but it is usually better to go with constructor injection. Here is a SO question about it.

With Funq, your configuration will then look like this:

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

Those two new interfaces and two classes and change to the MovieService didn't win you a lot, because Funq doesn't support auto-wiring. You will be the one who is wiring everything together manually. However, when you switch to a framework that does support auto-wiring, this design allows the container to inject the right dependencies without a problem, because there is no discussion about what to inject.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...