Generic IServiceLocator

30 views
Skip to first unread message

Justin Rudd

unread,
Oct 2, 2008, 4:37:00 AM10/2/08
to aut...@googlegroups.com
Chris Tavares just posted about the common service locator interface - http://www.tavaresstudios.com/Blog/post.aspx?id=32a656f5-e908-4a25-b6e3-1fecd287352a.  It looks fairly trivial to implement for Autofac.  The only one I've had any trouble with is GetAllInstances.  I could go through all the component registrations of the container and look through the Services of each one looking for a TypedService that matches and then activate that registration.  But I'm guessing there has to be an easier way.  Thoughts?

I'll post it to the list when I finish...

Justin Rudd

Nicholas Blumhardt

unread,
Oct 2, 2008, 12:07:05 PM10/2/08
to aut...@googlegroups.com
Hi Justin!

I have been thinking about this too.

Looping through registrations is possible (perhaps we could offer a configuration parameter?) but my preference would be to translate these calls into requests for IEnumerable<T> on the container.

My reasoning is that this matches Autofac's "opt-in" collection semantics.

Keen to discuss those semantics in detail at some point (when I have some more time.)

Hey are you in Redmond? I'd love to catch up and say "hi!"

Cheers,

Nick

Justin Rudd

unread,
Oct 2, 2008, 4:26:59 PM10/2/08
to aut...@googlegroups.com
I think a configuration parameter will work.  In looking at the docs on the interface, it would seem that GetAllInstances is supposed to get all the instances of the type from the container.  So if called like locator.GetAllInstances<IOutput>(), would return an enumerable of all the types that registered "As<IOutput>".  But I can also see where it would be useful to return the enumerable that someone explicitly registered.

To match the other implementations, returning the enumerable from the container directly should be turned on, not turned off.

Got caught up in some "pay the bills" work so I haven't been able to finish it.  Should be able to get back to it this afternoon.

As for Redmond, no.  I'm in the Bellevue office called Lincoln Square.  But it is quick shuttle ride to the campus.  Just look me up in outlook and let me know when you are free.  Right now I'm pretty open.

Justin

Daniel Cazzulino

unread,
Oct 2, 2008, 3:26:08 PM10/2/08
to aut...@googlegroups.com
I think IServiceLocator is a bad idea, so I wouldn't make the slightest change to Autofac to add any special support for it.

DI is about NOT doing opaque service locator injection...

Justin Rudd

unread,
Oct 2, 2008, 4:43:56 PM10/2/08
to aut...@googlegroups.com
No changes are being made.  I've built the adapter based on what is in the public API.  

As for being useful, I believe that it is in the same sense that a common logging interface is useful.  As a library developer, I don't want to force people to use my DI container just the same as I don't want to force people to use my logging choice (log4net, whatever).

As an application developer, your right.  It isn't that useful.

Nicholas Blumhardt

unread,
Oct 2, 2008, 4:44:20 PM10/2/08
to Autofac
Daniel - I agree so strongly I almost need to type this entire email
in CAPS.

There are a range of use cases where this library will be handy
though.

E.g. ASP.NET MVC depends on IControllerFactory.

It also ships with an optional ServiceLocatorControllerFactory.

SLCF depends on the generic IServiceLocator, so if you have an
implementation for your container you can do something like:

x.ControllerFactory = new ServiceLocatorControllerFactory(new
AutofacServiceLocator(myContainer));

This just cuts down on the code that has to be written to support new
frameworks.

The catch is that the framework must not depend on the generic service
locator - the only place that the coupling is acceptable is in the
same place we're currently doing it - a small, throwaway, independent
adapter class that can be used to turn calls on a specific interface
to calls on a generic one.

Glenn and I have had a lot of discussions lately about how to
discourage people from referencing IServiceLocator when really they
should reference a domain-specific registry or factory interface.

It is scary that 90+% of the use cases for this are *abuse*, but done
correctly the other 10% of use cases will really help encourage
diversity of choice in terms of IoC containers.

Once again, I agree with your point so strongly that I was initially
against even THINKING about creating such a thing, but now with some
time to reflect I've concluded that we shouldn't try to protect users
from themselves, and as always it is up to the user to get informed
and use this correctly.

Hope this wasn't too much of a rant for this generally quiet list :)

On Oct 2, 12:26 pm, "Daniel Cazzulino" <dan...@cazzulino.com> wrote:
> I think IServiceLocator is a bad idea, so I wouldn't make the slightest
> change to Autofac to add any special support for it.
>
> DI is about NOT doing opaque service locator injection...
>
> On Thu, Oct 2, 2008 at 1:07 PM, Nicholas Blumhardt <
>
> nicholas.blumha...@gmail.com> wrote:
> > Hi Justin!
>
> > I have been thinking about this too.
>
> > Looping through registrations is possible (perhaps we could offer a
> > configuration parameter?) but my preference would be to translate these
> > calls into requests for IEnumerable<T> on the container.
>
> > My reasoning is that this matches Autofac's "opt-in" collection semantics.
>
> > Keen to discuss those semantics in detail at some point (when I have some
> > more time.)
>
> > Hey are you in Redmond? I'd love to catch up and say "hi!"
>
> > Cheers,
>
> > Nick
>
> > On Thu, Oct 2, 2008 at 1:37 AM, Justin Rudd <justin.r...@gmail.com> wrote:
>
> >> Chris Tavares just posted about the common service locator interface -
> >>http://www.tavaresstudios.com/Blog/post.aspx?id=32a656f5-e908-4a25-b6....

Nicholas Blumhardt

unread,
Oct 2, 2008, 4:45:33 PM10/2/08
to Autofac
BTW that was a hypothetical ASP.NET MVC - I have no idea what those guys are planning, that's just an example :)

Jeremy Gray

unread,
Oct 3, 2008, 12:34:03 AM10/3/08
to Autofac
@Danial & Nicholas - Oh, how lovely it must be to live in a world
where your project was fully IoC/DI from the start, and where you have
no need for named instances. It must also be lovely to be able to
magically bootstrap your starting object without an initial call to a
DI-backed service locator (or to the DI container itself.)

The rest of us poor folks need ways to introduce IoC/DI into our
projects on an incremental basis. That requires some temporary
dependencies on a service locator. Sometimes we need named instances,
which will create a rather non-temporary dependency on a service
locator in a few key spots. We also need to keep shipping while we do
this. And since this is all happening over an extended period of time,
sometimes our first guess about which DI container to use will end up
not satisfying our needs. And since we all end up building roughly the
same set of abstractions around overloads of GetInstance (and
GetAllInstances), we might as well have at least one copy of a common
interface kicking around to make things just a bit more consistent
across projects. And that's all before having to deal with integrating
multiple unrelated groups' components in a single aggregated solution,
each with dependencies on a service locator. And and and.

You might think that "90+% of the use cases for this are *abuse*" but
I suspect that the vast majority if not all of that 90+% of use cases
are simply accounting for pragmatic realities of many projects.

Opinionated frameworks and tools are great things, and I certainly
appreciate the work that both of you have done and continue to do for
the community. That said, the subject matter at hand would surely
benefit from each of you coming across a bit less puritanical.

There's my rant for the day. :)

Jeremy

Nicholas Blumhardt

unread,
Oct 3, 2008, 1:10:19 AM10/3/08
to aut...@googlegroups.com
Funny - I still think the uses you're talking about are in that 10%!

I willingly submit myself to the pain of having to code service locators around the non-DI-friendly points. Each and every time I do it, I harden my will to fight for a brighter day, when we've finally moved all of our frameworks across!

Penance, Jeremy!

...Ok, so you're right - enough puritanism. Think these election debates are getting to me :)

Luke Schafer

unread,
Oct 3, 2008, 1:16:39 AM10/3/08
to aut...@googlegroups.com
I use a named-instance service locater. No complaints.

Win.

Nicholas Blumhardt

unread,
Oct 3, 2008, 1:17:56 AM10/3/08
to aut...@googlegroups.com
The reason that Autofac avoids a typical ResolveAll<X>() is that it is hard to change your mind about having that one, global collection for all of your implementers of X.

I started out trying to write DI applications based on type alone. I.e, if I wanted a foo, I resolved IFoo. There was just one. The service and the identity were one.

This didn't get too far. Eventually, I hit occasions where code in one place would want foo 'a' and code elsewhere really wanted foo 'b'. It sounds pretty obvious in hindsight.

I really like to extend the same separation of 'identity' and 'service' into the realm of collections, too.

In Autofac's model, you can easily transition from having one collection of IFoo to having several - it is just a matter of configuration.

In the typical 'ResolveAll' model, there is a discontinuity - if you start out with one global collection of IFoo, then decide that you really need two distinct ones, you've got to change more than just your configuration.

You can, of course, support almost anything on either model - it is just preference.

Cheers,

Nick

Jeremy Gray

unread,
Oct 3, 2008, 1:26:15 AM10/3/08
to Autofac
Hehe. For the record, I too would love to do without the various
"abuses" ;)

I have implemented something very similar to the IServiceLocator
abstraction that this is all about (heck, after all it was my alt.net
canada session that spawned this whole thing in the first place) but I
have yet to explicitly retrieve a named instance. That said, I have
used GetAllInstances in some key points where a variety of plugins get
hooked into the running application by way of the conventions we've
established and it has made for clear sailing at our extensibility
points.

I have gone one beyond the common IServiceLocator, however, that being
to add in the option to override a single dependency (now that
multiple DI containers support doing so, otherwise I would not have
added it) and man, is it ever nice to be able to pass a single piece
of context and have the rest of the dependencies resolved by the
container. Yes, I'm injecting into entities. :)

That said, we get away with this in my current client project as our
domain objects are much lower in quantity (at least relative to the
available system resources) are extremely long-lived (relative to the
usual), and our only registered singleton component is the locator
itself (put that in your pipe and smoke it ;) ) as the rest of our
components are all instantiated per-call (it's just that the returned
object graph gets to stick around for a very long time :) .)

Jeremy

On Oct 2, 10:10 pm, "Nicholas Blumhardt"
<nicholas.blumha...@gmail.com> wrote:
> Funny - I still think the uses you're talking about are in that 10%!
> I willingly submit myself to the pain of having to code service locators
> around the non-DI-friendly points. Each and every time I do it, I harden my
> will to fight for a brighter day, when we've finally moved all of our
> frameworks across!
>
> Penance, Jeremy!
>
> ...Ok, so you're right - enough puritanism. Think these election debates are
> getting to me :)
>

Luke Schafer

unread,
Oct 3, 2008, 1:42:00 AM10/3/08
to aut...@googlegroups.com
I might be missing something, but optional overrides exist, and always work with factory scoped registrations.

Jeremy Gray

unread,
Oct 3, 2008, 2:40:34 AM10/3/08
to Autofac
No, you're not missing anything. We're using override functionality in
a few places in my current project. It works nicely, though I am
trying to limit its usage and have already restricted it to allowing
just one dependency to be overridden (if the calling code knows about
too many of the type's dependencies, it starts to get a bit too smelly
for my taste.) As for scoping, we've gone with transient instances for
all but the locator itself, as it is needed that way in some cases and
doesn't hurt in the others. It just keeps things nice and consistent,
that's all. :)

Full disclosure: we're using structuremap for the project I've been
describing, but only then because it had slightly more obvious
supporting pieces for convention scanning. Autofac was in a VERY close
second place, and even then I suspect it would be a tie now because
I've had to put in some of my own assembly scanning code, enough to
almost deprecate what SM provided. I'll probably migrate at some
point, if only to prove that the abstractions really can handle having
the container swapped out from under them as was the intent of the
design. ;)

Jeremy

Daniel Cazzulino

unread,
Oct 3, 2008, 9:56:58 AM10/3/08
to aut...@googlegroups.com
It was getting too bit so it's a blog post now :)

http://www.clariusconsulting.net/blogs/kzu/archive/2008/10/03/WhatisallthefuzzaboutthenewcommonIServiceLocator.aspx

Copied here for convenience:
-----
There's been some excitement lately about the introduction of a common IServiceLocator that all major DI containers apparently will provide.

Unless you're building an "extensible framework leveraging framework consumer selectable IoC containers", don't sweat it too much, the interface was NOT created for you!

Let me reiterate: adding a dependency on IServiceLocator to your classes is NOT a good idea. When you do so, instead of an explicit and self documenting dependency on an external object, you're tunneling this locator that now hides to the class consumers which are its true dependencies. This is BAD, as it requires users to go to your class documentation (and hope it's updated) rather than its constructor to see what it needs to operate. If you've done any kind of work extending VS you know how bad this can get.

I've seen comments that this is just a "purist" view and that the real world ain't like this and you still need it.

 

Somehow some people seem to think that we (those who have contributed some open source framework of sorts) don't work on real projects and live in an ideal world and make frameworks for these ideal situations which don't actually translate to your real world. That we somehow just dream about the ideal conditions and spit a framework accordingly.

Oh that's so wrong ;). I wish it were that way sometimes, though, hehe.

I speak from experience in actual projects (working on two of them simultaneously these days, one of them fairly large), and let me repeat: YOU DON'T NEED A DEPENDENCY ON IServiceLocator in your business objects.

What you might need is to change your DI framework of choice if it doesn't allow you to get rid of that dependency ;).
Let me elaborate on some of the situations that supposedly require so:

Named instances: just move the named instance requirement outside the bz class and into the container configuration:

builder.Register<IBar>(c => new Bar(c.Resolve<IFoo>("a"))); Need all instances of X: again, move the dependency out of your bz class and into configuration!

builder.Register<IBar>(c => new Bar( /* get an IEnumerable<T> from container, or whatever */  )); Need to create new instances of components inside your bz class (that is, you need a factory?): register a Func<T> factory for your component!

builder.RegisterGeneratedFactory<Func<IBar>>();

ctor Foo(Func<IBar> barFactory);

// Foo needs a new bar?var b = barFactory();
If you can come up with a real world scenario (which does NOT involve authoring a framework such as ASP.NET MVC, MonoRail, etc.) where a good DI container cannot save you from having that dependency, only then I'll believe you need IServiceLocator.

I'd argue that people that should care/use such a thing is even less than 1%. That's why I wouldn't go about publicizing this thing so much, and you should hardly care about it. I can see it applied by (non-DI) framework authors to enable different DI frameworks to be plugged-in, but I hardly see how anyone doing "real world" work would benefit rather than detriment from its use.

 

There you have my rant too :)

Daniel Cazzulino

unread,
Oct 3, 2008, 10:33:43 AM10/3/08
to aut...@googlegroups.com
copying from the HTML mangled the important part:


YOU DON'T NEED A DEPENDENCY ON IServiceLocator in your business objects.

...

  • Named instances: just move the named instance requirement outside the bz class and into the container configuration:

    builder.Register<IBar>(c => new Bar(c.Resolve<IFoo>("a")));

  • Need all instances of X: again, move the dependency out of your bz class and into configuration!

    builder.Register<IBar>(c => new Bar( /* get an IEnumerable<T> from container, or whatever */  ));

  • Need to create new instances of components inside your bz class (that is, you need a factory?): register a Func<T> factory for your component!

    builder.RegisterGeneratedFactory<Func<IBar>>();

    ctor Foo(Func<IBar> barFactory);

    // Foo needs a new bar?var b = barFactory();


Nicholas Blumhardt

unread,
Oct 3, 2008, 10:41:57 AM10/3/08
to aut...@googlegroups.com
Only one thing - RegisterGeneratedFactory<Func<Bar>> doesn't work in 1.3 - needs to be a hand-written delegate type. Now that you draw attention to it again though, it seems like a really good way to use the feature...

Daniel Cazzulino

unread,
Oct 3, 2008, 11:13:17 AM10/3/08
to aut...@googlegroups.com
in the current stable version it works :)

Nicholas Blumhardt

unread,
Oct 3, 2008, 4:31:36 PM10/3/08
to aut...@googlegroups.com
Aah right you are :) So long as you don't require any Func parameters. Well spotted!

Justin Rudd

unread,
Oct 3, 2008, 8:07:51 PM10/3/08
to aut...@googlegroups.com
I got bogged down with "pay the bills" work and didn't get a chance to implement Nick's suggestion of return IEnumerable<TService> when using GetAllInstances.  Instead of waiting, I just attached what I do have done.  If anyone wants to add the missing pieces, feel free.  Otherwise I'll take a crack this weekend.

On Thu, Oct 2, 2008 at 1:37 AM, Justin Rudd <justi...@gmail.com> wrote:
ServiceLocatorAdapter.cs

Daniel Cazzulino

unread,
Oct 3, 2008, 9:19:40 PM10/3/08
to aut...@googlegroups.com
yup, indeed :)
looking at how to port it to the 2.0 branch... looks like you did a serious refactoring... kind of hard to find stuff now that I'm more used to the "old" way...

Nicholas Blumhardt

unread,
Oct 3, 2008, 9:32:31 PM10/3/08
to aut...@googlegroups.com
Might be better porting backwards... "2.0" in its current state is an internal redesign, so it will probably end up churning a lot before it settles down anyway. Not to mention that key pieces like open generic type support haven't been implemented over there yet.

Daniel Cazzulino

unread,
Oct 3, 2008, 11:38:27 PM10/3/08
to aut...@googlegroups.com
oki, moving to trunk then...

Rinat Abdullin

unread,
Oct 12, 2008, 1:54:09 PM10/12/08
to Autofac
Damn, I should've read the groups instead of rushing in with the
code)))

On Oct 4, 6:07 am, "Justin Rudd" <justin.r...@gmail.com> wrote:
> I got bogged down with "pay the bills" work and didn't get a chance to
> implement Nick's suggestion of return IEnumerable<TService> when using
> GetAllInstances.  Instead of waiting, I just attached what I do have done.
>  If anyone wants to add the missing pieces, feel free.  Otherwise I'll take
> a crack this weekend.
>
> On Thu, Oct 2, 2008 at 1:37 AM, Justin Rudd <justin.r...@gmail.com> wrote:
> > Chris Tavares just posted about the common service locator interface -
> >http://www.tavaresstudios.com/Blog/post.aspx?id=32a656f5-e908-4a25-b6....
> >  It looks fairly trivial to implement for Autofac.  The only one I've had
> > any trouble with is GetAllInstances.  I could go through all the component
> > registrations of the container and look through the Services of each one
> > looking for a TypedService that matches and then activate that registration.
> >  But I'm guessing there has to be an easier way.  Thoughts?
> > I'll post it to the list when I finish...
>
> > Justin Rudd
>
>
>
>  ServiceLocatorAdapter.cs
> 3KViewDownload
Reply all
Reply to author
Forward
0 new messages