Windsor: auto-register types that have dependency in constructor

84 views
Skip to first unread message

queen3

unread,
Nov 8, 2009, 8:43:42 AM11/8/09
to Castle Project Users
Most of the examples I see for Castle Windsor to do auto-register of
types depend on deriving from some IFoo. Or, from base class. However,
I often have simple components (services) that just require IFoo in
the constructor:

public class AddressViewModel
{
public AddressViewModel(ICountryRepository countries)
{
this.Countries = countries.GetAll();
}
}

Here AddressViewModel is created by ASP.NET MVC generic ActionFilter
that transforms domain model into view model - automatically. It asks
Windsor to create the destination view model. I have many view models,
and I don't really want to manually register all of them in Windsor.
From my point of view, if I ask Windsor to create AddressViewModel, it
should check if its constructor has registered dependencies (maybe
even nested), and if so - create them and then create AddressViewModel
- instead of throwing "not registered".

How do I make Windsor to automatically register/recognize such cases?
I see two ways:

1. Browse all types in assembly, get their constructors, check if any
of the constructor's parameter is registered in Windsor... and
register it. The problem is that Service can depend on Service2 ->
IFoo... I want CONTAINER to do this, not me.
2. Somehow extend Windsor (facility, etc - I'm not expert here) so
that the above happens during "Resolve" call - so that I don't need to
browse all the meaningless types in all assemblies.
In both cases, however, I'll need a way to ask Windsor "Is type T your
dependency - directly or indirectly via nested constructor?".

I really hate duplication, so I don't see why I need to manually
register something that Windsor does already know about and can
create.

Here's the code that I use now. I'm really not expert in Windsor so
I'm not sure if the code is OK - but it works.

var dependencies = container.Kernel.GetAssignableHandlers(typeof
(object));
// for all ViewModel classes - purely optimization, to avoid
browsing all types
foreach (var type in typeof(ViewModel<>).Assembly.GetTypes().Where
(x => x.Name.EndsWith("ViewModel")))
{
// get all constructors and their parameters
var ctorArgs = type.GetConstructors().SelectMany(x =>
x.GetParameters());
// ViewModel can be resolved if any of its ctors has Windsor-
registered arguments
// TODO: add checks for IList<Type>, etc... really Windsor
should do this
var canBeResolved = dependencies.Any(dep => ctorArgs.Any(a =>
a.ParameterType.IsAssignableFrom
(dep.ComponentModel.Service)));
if (canBeResolved)
container.AddComponent("viewModel" + type.Name, type);
}

However, I would better have Windsor (or my extension) do this during
resolve-time, because brosing ALL types is a bit overkill in my
opinion, even though I narrow it with name filter. Is it possible? Is
there a better way?

Germán Schuager

unread,
Nov 8, 2009, 9:00:13 AM11/8/09
to castle-pro...@googlegroups.com
Try something like this:

container.Register(
   AllTypes.Pick()
      .FromAssembly(typeof(ViewModel<>).Assembly)
      .If(c => c.Name.EndsWith("ViewModel))
      .WithService.Base()        // <---- not sure about this line
   );

Krzysztof Koźmic

unread,
Nov 8, 2009, 9:58:25 AM11/8/09
to castle-pro...@googlegroups.com
Generally I use some kind of conventions for this:

like

Foo.Controllers.BarController
Foo.ViewModes.BarViewModel
Foo.Repositories.BarRepository

then it's easy to register all things to the container based on the
convention. (usually you want to register ALL controllers AND all
viewModels AND all repositories so you don't even have to concern
yourself with name matching)
And if youre not always conforming to the convention youll just have few
outstading services to register explicitly.

It looks to me like you're having more of a design consistency problem
than Windsor problem

Krzysztof

Germán Schuager wrote:
> Try something like this:
>
> container.Register(
> AllTypes.Pick()
> .FromAssembly(typeof(ViewModel<>).Assembly)
> .If(c => c.Name.EndsWith("ViewModel))
> .WithService.Base() // <---- not sure about this line
> );
>
> On Sun, Nov 8, 2009 at 10:43 AM, queen3 <sergey.pr...@gmail.com
> <mailto:sergey.pr...@gmail.com>> wrote:
>
>
> Most of the examples I see for Castle Windsor to do auto-register of
> types depend on deriving from some IFoo. Or, from base class. However,
> I often have simple components (services) that just require IFoo in
> the constructor:
>
> public class AddressViewModel
> {
> public AddressViewModel(ICountryRepository countries)
> {
> this.Countries = countries.GetAll();
> }
> }
>
> Here AddressViewModel is created by ASP.NET <http://ASP.NET> MVC

Mauricio Scheffer

unread,
Nov 8, 2009, 10:38:39 AM11/8/09
to Castle Project Users

queen3

unread,
Nov 8, 2009, 12:55:22 PM11/8/09
to Castle Project Users
I agree with you in general. However I do not agree that all view
models are to be registered - I'd say I have about 5-10% that have to,
other classes do not use repositories or other dependencies (not every
page needs to fill dropdown from independent repository). So it's
still a bit of overkill (in my opinion) to register all view models
just because of some of them. Notice that my code only registers those
classes that require dependencies, not all view models.

For controllers and repositories it's almost 100% so the trick works.

Of course it's a matter of taste, I do not experience any performance
problem because I register additional view models (though I didn't
measure). I just feel it's a bit ugly to perform unneccessary
registrations.

On Nov 8, 4:58 pm, Krzysztof Koźmic <krzysztof.koz...@gmail.com>
wrote:
> Generally I use some kind of conventions for this:
>
> like
>
> Foo.Controllers.BarController
> Foo.ViewModes.BarViewModel
> Foo.Repositories.BarRepository
>
> then it's easy to register all things to the container based on the
> convention. (usually you want to register ALL controllers AND all
> viewModels AND all repositories so you don't even have to concern
> yourself with name matching)
> And if youre not always conforming to the convention youll just have few
> outstading services to register explicitly.
>
> It looks to me like you're having more of a design consistency problem
> than Windsor problem
>
> Krzysztof
>
>
>
> Germán Schuager wrote:
> > Try something like this:
>
> > container.Register(
> >    AllTypes.Pick()
> >       .FromAssembly(typeof(ViewModel<>).Assembly)
> >       .If(c => c.Name.EndsWith("ViewModel))
> >       .WithService.Base()        // <---- not sure about this line
> >    );
>
Reply all
Reply to author
Forward
0 new messages