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

你。 提交于 2019-11-27 05:25:44

问题


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


回答1:


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.




回答2:


Although Funq doesn't support Auto wiring, ServiceStack implementation of it does. The latest version of ServiceStack includes the Funq.Container overloads:

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

So in Steven's example you can also do:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>();

And it will automatically register the dependencies for you.




回答3:


Thought I'd chip in my 2 cents here, though I realise the question is pretty old. I wanted to access a transactional DB and a logging DB from ServiceStack and this is how I ended up doing it from the AppHostBase Configure() method:

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

By default, the "MyTransactionalDB" is used when opening a connection from the factory, but I can explicitly access the logging DB from a service via:

        using (var db = DbFactory.Open("LoggingDB"))
        {
            db.Save(...);
        }



回答4:


Try using the Repository pattern instead of this IoC (which just complicates things unnecessarily). The code above seems not to work. Suspect something has changed. I'm still unclear as to how registering an IDbConnectionFactory magically populates the IDbConnection property. Would love some explanation around this. If someone ever does get this working using the ServiceStack IoC container.. then I'd love to see how. And it would be hugely benefitial to update the SS docs (I'm quite happy to do it)



来源:https://stackoverflow.com/questions/8764125/how-to-register-multiple-idbconnectionfactory-instances-using-funq-in-servicesta

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!