Factory Methods and IServiceLocator disposal

8 views
Skip to first unread message

Darren Cauthon

unread,
Jul 3, 2010, 8:02:49 AM7/3/10
to MVC Turbine
- Factory Method

I've created a new feature for the Turbine service locator, the
ability to register a factory method. This means that you can do the
following:

locator.Register<IRepository>(() => new Repository());

When you call locator.Resolve<IRepository>(), the delegate you passed
will be invoked and the result will be returned.

All of the IoC containers support this feature, so adding it in wasn't
too difficult. I posted earlier about the trouble I was having with
Windsor, but I got that worked out. I think I'd like to add the
ability to pass in a Func<IServiceLocator, T> delegate as well, just
to make a delegate that uses the service locator look a little less
suspicious.

Since the service locator was intentionally meant to be simple and the
lowest-common-denominator between all of the containers, I'd like to
defend this new feature. :) I think the service locator should be
kept simple and at an abstraction level where developers think about
how to best use IoC instead of their favorite container. I'd be
suspicious of most requests to update the service locator itself,
especially when anybody is free to extend it however they wish.
However, I think this is a little different. Providing a short,
simple method to resolve a type is, in a way, already what developers
do when they register types. And, in many situations this is enough
to prevent developers from breaking LSP by casting up to their
favorite service locator when they want to do something container-
specific.

For example, if I want to store and resolve a container registration
in session, I can do so without switching to Unity and using one of
its lifetime managers. I think this even makes writing blades that
work across all containers easier.

The branch is here: http://github.com/darrencauthon/mvcturbine/tree/ioc_factory_method

- Disposal

All of that said, there is one practical use of this right now, and
it's directly in the Turbine framework. We register the
IServiceLocator with itself, so you can resolve IServiceLocator
anywhere you need. That's great, but with some IoC containers
(StructureMap and Unity) get caught in an endless loop when instances
of themselves are registered. During disposal, they call dispose on
all of their children. If one of those children is the container
itself, Dispose is called on it, which then calls Dispose again, and
again.... you get the picture. The symptom users will see is a server
shutdown every time they rebuild their MVC application. I wrote a
unit test (http://bit.ly/aX7prs) that reproduces the issue, and it's
as simple as:

using (locator.Batch())
locator.Register<IServiceLocator>(locator);
locator.Dispose();

This won't just fail, it will shut down your test runner. :) If I
replace it with:

using (locator.Batch())
locator.Register<IServiceLocator>(() => locator);
locator.Dispose();

StructureMap and Unity will dispose, but then Windsor got caught in an
endless loop. (Javier, I don't know how you got these guys to behave
together.) I had to change how Windsor registered the IServiceLocator
in order to get it to fall in line.

Let me know if you have any questions.


Darren
Reply all
Reply to author
Forward
0 new messages