19

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

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jeff Mitchell
  • 1,459
  • 1
  • 17
  • 33
  • Can you show some code? I think we can give you some tips on the design of your application, but for this, we need more insight of the actual design. It would be interesting to see in what services you inject those `IDbConnectionFactory` intances in, and what those services do with those `IDbConnectionFactory` dependencies. – Steven Jan 07 '12 at 00:23
  • Note however that Funq is a very simplistic IoC container (some might even argue it isn't a IoC container at all), and everything must be wired by hand. However, you can inject everything you want in every service you create. – Steven Jan 07 '12 at 00:25
  • I updated the question, making it a bit more clear and found your article on Simple Injector. I'm Giving that a read through now in hopes of deepening my understanding of IoC. – Jeff Mitchell Jan 07 '12 at 03:24
  • Since you're looking at Simple Injector, perhaps you're interesting in the comparison between [Simple Injector and Funq](http://www.codeproject.com/KB/library/simpleinjector.aspx?msg=3878659#xx3878659xx). – Steven Jan 07 '12 at 20:14

5 Answers5

15

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.

Community
  • 1
  • 1
Steven
  • 166,672
  • 24
  • 332
  • 435
  • 1
    Thank you for the thorough answer. This exactly what I was looking for. – Jeff Mitchell Jan 07 '12 at 20:39
  • 5
    Note: ServiceStack does actually support Auto wiring with its Funq.Container - see my answer. – mythz Jan 09 '12 at 20:48
  • 1
    @Steven What if the databases share the same model? i.e. Multi tenant – Stephen Patten Oct 01 '14 at 12:18
  • @StephenPatten: In that case it's okay to have one single abstraction to use and you need to solve this in other ways. For instance by injecting an `ITenantContext` dependency of some sort that allows classes to select the proper database. For instance inject `ITenantContext` into your `DbConnectionFactoryImpl` and use is to select the correct connection string (assuming that each tenant has its own database). – Steven Oct 01 '14 at 12:28
11

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.

mythz
  • 141,670
  • 29
  • 246
  • 390
  • Quite strange for a Service Framework implementation to have such a feature. This seems like a feature for an IoC container, and not for ServiceStack. – Steven Jan 09 '12 at 21:25
  • 1
    Agreed, I posted this a long time ago in Funq's mailing list but nothing came of it http://funq.codeplex.com/workitem/2158 – mythz Jan 09 '12 at 21:32
  • 2
    The Funq framework seems to be abandoned for a long time already. Why don't you switch to Simple Injector as default IoC framework for ServiceStack? Since ServiceStack seems to be an high performance framework, Simple Injector is a good fit, since it is the fastest IoC framework in the field. I think ServiceStack is really nice, btw. – Steven Jan 10 '12 at 08:42
  • Besides, it would be nice to see Simple Injector added to the benchmarks: http://www.servicestack.net/benchmarks/. – Steven Jan 10 '12 at 08:56
  • 2
    In response with our choice of Funq: Funq is a completed library and does exactly what it has set out to do. It's an example of an elegantly written and expressive library delivering 90% of the functionality at only a fraction of the code-base of other heavy IOC's. We're maintaining and enhancing our own embedded port of it, adding features whenever we need them. If there's anything we want that's missing, we added it ourselves. Other contributors are invited to do the same. – mythz Mar 18 '13 at 21:10
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(...);
        }
vipes
  • 922
  • 1
  • 9
  • 17
1

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)

The Huff
  • 365
  • 1
  • 5
  • 15
  • Regarding IDbConnectionFactory, you can refer to the ServiceStack OrmLite code: public virtual IDbConnection Db { get { return this.db ?? (this.db = OrmLiteConnectionFactoryExtensions.Open(this.TryResolve())); }} – labilbe Oct 15 '13 at 11:59
1

You can also use a dictionnary

Create a enum with your database Key Name

public enum Database
    {
        Red,
        Blue
    }

In Startup.cs, create a dictionary of function that open a new SqlConnection, then inject the dependency dictionary as Singleton

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

After you can get the instance od the dependency on object constructor like so:

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

It's clean and readable ;)

G Clovs
  • 2,442
  • 3
  • 19
  • 24