How to make an AutoFac service locator

947 views
Skip to first unread message

mcintyre321

unread,
Jun 27, 2008, 3:07:08 PM6/27/08
to Autofac
Hi all! I'm just trying to get to grips with IoC, DI and of course
AutoFac. My class Foo has a dependency on class IBar, but
unfortunately class X is a LinqToSql class and as such gets
instantiated by the framework, so I can't use constructor injection,
so I think I need to use a Service Locator. Now to use a service
locator I need to call container.Resolve<IBar>() - where does my class
get the reference to the container object from? Should I create a
static class somewhere with an object called container on it? Is
there something static built into AutoFac to handle this?
thanks!

Nicholas Blumhardt

unread,
Jun 27, 2008, 7:04:55 PM6/27/08
to aut...@googlegroups.com
Hi 321,

I presume X and Foo are the same class in your example?

If this class is a domain object, and you're just getting started with DI, I recommend that you follow the advice of Bauer & King in Hibernate in Action (there's an example in there) and design your service layer so that your domain objects can be implemented independently of (DI) services.

E.g. in your service/controller layer, instead of:

var quote = stock.GetCurrentQuote(); // quote service is injected into domain object 'Stock'

use something like:

var quote = quoteService.GetCurrentQuote(stock); // quoteService is injected into (current) controller

This does have the side-effect of limiting the amount of business logic that can be crunched down into the domain model. IMHO domain objects benefit greatly from being able to query repositories, but which other services could be safely injected is up for debate. (The point that will be raised is that if IQuoteService here is a remote invocation, robustness and performance could be very hard to manage.)

It is possible to inject dependencies into domain objects (generally through property injection executed within a hook provided by the ORM,) but there isn't any current consensus on when this is appropriate, and I've never seen an example using Linq to SQL. Better not to jump straight into this territory right away unless you're really keen :)

Hope this helps,

Nick

Luke Schafer

unread,
Jun 27, 2008, 7:46:51 PM6/27/08
to aut...@googlegroups.com
I'd say create a singleton (many tutes on how to do this) then either:

Wrap the container such that you can swap containers at any time (not that you'd want to swap from autofac, just sayin...), or
Use the singelton to extend the container to create the singleton (not sure how much control you have over this... override should be your friend here)

You could even use this to bundle the builder and container - allow registrations then lazy-build the container on first access

It's early morning and I was working really late, apologies for the crappy explainations

mcintyre321

unread,
Jun 28, 2008, 6:31:58 AM6/28/08
to Autofac
Yep X and Foo are definately one and the same. Oops :)

I have spotted http://kohari.org/2008/06/18/playing-nice-with-service-locators/
on Nate Kohari's blog which I guess has answered my problem. The
reason I'm not passing the service in is that its a kind of mock
DateTime.Now Clock class and not a remote call. I did in fact make it
a singleton, but I've heard they are a bit of an anti pattern compared
to a service locator, so I'm going to follow the post above and see
where it gets me. Thanks for you help guys!

Nick, I'm not sure thats the approach I need. The service I am trying
to inject is actually a Clock object, a bit like DateTime.Now, but for
processing stuff in the future and past, and is not held remotely.
> > On Sat, Jun 28, 2008 at 5:07 AM, mcintyre321 <mcintyre...@gmail.com>
> > wrote:
>
> >> Hi all! I'm just trying to get to grips with IoC, DI and of course
> >> AutoFac. My class Foo has a dependency on class IBar, but
> >> unfortunately class X is a LinqToSql class and as such gets
> >> instantiated by the framework, so I can't use constructor injection,
> >> so I think I need to use a Service Locator. Now to use a service
> >> locator I need to call container.Resolve<IBar>() - where does my class
> >> get the reference to the container object from? Should I create a
> >> static class somewhere with an  object called container on it? Is
> >> there something static built into AutoFac to handle this?
> >> thanks!- Hide quoted text -
>
> - Show quoted text -

jonathan...@hotmail.com

unread,
Jun 28, 2008, 9:36:26 AM6/28/08
to Autofac
We've actually got something similar to what you're doing - we have an
interface called ITimeService. The biggest reason for it is to
properly mock classes that have a dependency on time. With regards to
the singleton being an anti-pattern, it's only that way when you do
things like call a static location, e.g. System.Date.Now - because it
can't be swapped. But if you provide a shared instance
(SingletonScoped() with the Autofac container), the instance can
easily be swapped for testing and another mock version provided.

On Jun 28, 4:31 am, mcintyre321 <mcintyre...@gmail.com> wrote:
> Yep X and Foo are definately one and the same. Oops :)
>
> I have spottedhttp://kohari.org/2008/06/18/playing-nice-with-service-locators/
> > - Show quoted text -- Hide quoted text -

Nicholas Blumhardt

unread,
Jun 28, 2008, 9:02:29 PM6/28/08
to Autofac
Hi Harry,

In your situation the difference between the DI and non-DI solutions I
described would probably involve passing 'now' into the domain object
methods that require the current time, rather than having the domain
objects get this value from the clock service. Not flash, I agree.

Service Locator is a sound pattern, but as soon as you introduce it
into a DI-managed application, you lose much of the predictability
that justifies using DI in the first place (classes no longer
advertise their dependencies through their constructor parameters and/
or properties.) Go too far down that path and you might as well do
service location throughout.

Tough situation to be in.

If it is at all possible, you might consider doing property injection
into your domain objects after all. It is feasible that this could be
done by hand for a few classes - e.g. Foo.TimeService =
container.Resolve<ITimeService>().

Otherwise, you need to find a location in your app from which you can
call container.InjectInto(myInstance) for each loaded domain object.

At the end of the day, the best solution might turn out to be Service
Locator, but exploring your options first is a good move.

Building a service locator with Autofac, BTW, is a bit trickier than
with other containers, because of the need to always use the innermost
nested container for dependency resolution. You can take a look at the
ASP.NET integration and its ContainerProvider class for some clues as
to how this should be done (your static Service Locator in the domain
layer has to be wired to something like IContainerProvider rather than
IContainer, so that when service location is performed the current
container can be used.)

Cheers,

Nick
Reply all
Reply to author
Forward
0 new messages