How to do service override in Unity

Sep 10, 2008 at 11:32 AM
Edited Sep 10, 2008 at 1:43 PM
Hi,

I'm trying to rewrite a sample application I created from Castle Windsor to Unity, and I'm stuck with this piece of code:

            container.Register(
                Component.For<IPrinter>().ImplementedBy(MyOtherImplementation).Named("Printer2").
                    Interceptors(new InterceptorReference(typeof(EvilInterceptor))).Anywhere.
                    Parameters(Parameter.ForKey("colorer").Eq("${Printer2.colorer}")));

It does three things:
  1. Registers type represented by MyOtherImplementation as service IPrinter with name Printer2
  2. Adds an interceptor of type EvilInterceptor
  3. Tells Windsor that when building up object of type MyOtherImplementation, for parameter named colorer should be used object registered with the name Printer2.colorer
How can I do the same thing in Unity?
I know how to do just number 1.
AFAIR number 2 is beyond Unity's capabilities at the moment.
can number 3 be done?

Thanks.

Sep 10, 2008 at 5:23 PM
We don't work exactly like Windsor. You can approximate it, though. You are correct that we don't have interception (working on it now).

As for the parameters, we don't have a general "map this parameter name to this value". You can, however, specify values for constructor and properties.

For example, if Colorer was a property, you could do:

container.RegisterType<IPrinter, MyOtherImplementation>("Printer2", new ContainerControlledLifetimeManager())
    .Configure<InjectedMembers>()
        .ConfigureInjectionFor<MyOtherImplementation>("Printer2",
            new InjectionProperty<IColorer>("Colorer", new ResolvedParameter<IColorer>("Printer2.colorer")));

If you were using the default IColorer, you could just say typeof(IColorer) instead of using the ResolvedParameter object.

           
Sep 11, 2008 at 10:18 AM
Thanks. I've made it work. There's one thing that needs clarification though.
When I want to specify explicitly constructor parameter, is it a all-or-nothing game?

With InjectionConstructor I have to specify values for ALL parameters, as that's what Unity seems to be using to decide which constructor to use
If I have one constructor for MyOtherImplementation:

public MyOtherImplementation(IConsoleColorer colorer){}

I specify the parameter like this:
                ConfigureInjectionFor(MyOtherImplementation, "Printer2",
                                      new InjectionConstructor(new ResolvedParameter<IConsoleColorer>("Printer2.colorer")));

What if the constructor had a lot more parametes, and I wanted to just say, "for that parameter use this value, and the rest figure out by yourself".
Can that be done?
Sep 12, 2008 at 5:12 PM
It can be done, sort of. ;-)

Assuming you just want default values for each of the other parameters, you can just specify the type. You do need all the types of parameters to tell the container which constructor to pick.

So, if you had IColorer and IOutputStream as parameters, and you just wanted the default IOutputStream, you can do:

ConfigureInjectionFor<MyOtherImplementation>("Printer2",
    new InjectionConstructor(new ResolvedParameter<IConsoleColorer>("Printer2.colorer"), typeof(IOutputStream));

-Chris

Sep 15, 2008 at 7:50 AM
Hi Chris,

To be crystal clearm by default IOutputStream do you mean default(IOutputStream) ie null, or the default instance registered with the container, as oposed to named instance pointed to by new ResolvedParameter<IConsoleColorer>("Printer2.colorer") ?

What about a case, when all I know about the type behind the interface is the string containing its name and assembly that holds it, and the fact that it implements the interface. When I can't know anything about its constructors, and all I know is that somehow, either by propertry or by constructor it does have a dependency on IConsoleColorer, and I want to specify that it should use "Printer2.colorer", but not be explicit about how that dependency should be injected. Can Unity figure it out on its own?


Sep 16, 2008 at 7:54 PM
By default IOutputStream I mean the default instance registered in the container (i.e. the unnamed registration).

The latter case you describe is not something Unity can figure out on it's own; you'll need to come up with some kind of convention and possibly extend the container to know about that convention.

Sep 27, 2008 at 6:42 PM
Edited Sep 27, 2008 at 7:01 PM
This is a hot topic for me too. The issue for me is I have one constructor paramter that needs a specific named dependency, but the others should just use the defaults. Having to specify all or nothing means I have to update the ConfigureInjectionFor hooha when I add additional dependencies. The container goes from life changing freedom to a fragile management fiasco. Okay, that was a little dramatic but you get the point...

I am super impressed with the extensibility of Unity and I'm sure I could create the behavior I want with a point in the right direction. Of course, I would like to see native support for this.

Instead of

ConfigureInjectionFor<MyConcreteService>(new InjectionConstructor([all parameters so unity knows which constructor to pick]))

maybe something like:

ConfigureInjectionFor<MyConcreteService>(new ResolvedParameter<IMyDependency>("use this named dependency for whatever constructor unity picks")
Sep 27, 2008 at 7:03 PM
Wow, don't use chrome to post messages on codeplex! I just burned about 30 minutes and lost a few more hairs trying to figure out why my formatting got all crazy.