Castle Windsor new feature – dynamic parameters from registration site

UPDATE:

I renamed the method from WithParameters to DynamicParameters to avoid confusion and be consistent with Parameters method which is used for static parameters.

I just committed small new feature to Castle Windsor, that I think can nicely clean up your code. It remedies the following problem:

Problem

What if you have a component that relies on a dynamically provided primitive value? Things like current request’s Uri, or DateTime.Now?

public class UsesCurrentTime
{
   UsesCurrentTime(DateTime currentTime)
   {
      Console.WriteLine("Current time is {0}”, currentTime);
   }
}

Solution – the old way

Until now you had two choices:

  • wrap the dependency in a service, like ICurrentUriProvider, or IClock and take dependency on that interface
    public class UsesCurrentTime
    {
       UsesCurrentTime(IClock currentTime)
       {
          Console.WriteLine("Current time is {0}", currentTime.Now);
       }
    }
  • in the code using that service, reference the container and pull the service yourself, instead of having it injected.
    public class Uses_UsesCurrentTime
    {
       private IKernel container;
     
       public void DoSomethingWithCurrentTime()
       {
          var service = container.Resolve<UsesCurrentTime>(new {currentTime = DateTime.Now});
          // do something with the service here
       }
    }

Neither of these approaches is ideal. The new feature I mentioned is here to save the day. It basically lets you take the best of both approaches, without paying their price. You get to pass the parameters without additional layer of indirection, and without referencing container and pulling the service manually.

Solution – the new way

To use it, we need to use a new method on the fluent registration API: DynamicParameters, like this.

kernel.Register(
    Component.For<UsesCurrentTime>()
        .LifeStyle.Transient
        .DynamicParameters((kernel, parameters) => parameters["currentTime"] = DateTime.Now));

the method takes a delegate that will be invoked when the component is being resolved, but before any actual resolution, parameter matching, appropriate constructor searching etc happens. It gives you access to two things: the container itself, and the dictionary of parameters, that were passed from the call site. You can then inspect the parameters, add new, remove them, etc.

What’s more interesting – you can use it not only for primitives. You can also dynamically override components.

kernel.Register(
    Component.For<ICustomer>()
        .ImplementedBy<CustomerImpl>()
        .Named("defaultCustomer"),
    Component.For<ICustomer>().ImplementedBy<CustomerImpl2>()
        .Named("otherCustomer")
        .Parameters(
            Parameter.ForKey("name").Eq("foo"), // static parameters, resolved at registration time
            Parameter.ForKey("address").Eq("bar st 13"),
            Parameter.ForKey("age").Eq("5")),
    Component.For<CommonImplWithDependancy>()
        .LifeStyle.Transient
        .DynamicParameters((k, d) => // dynamic parameters
        {
            var randomNumber = 2;
            if (randomNumber == 2)
            {
                d["customer"] = k.Resolve<ICustomer>("otherCustomer");
            }
        }));
 
var component = kernel.Resolve<CommonImplWithDependancy>();
Assert.IsInstanceOf<CustomerImpl2>(component.Customer);

This test will pass.

Technorati Tags:

Posted 12-10-2009 11:01 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

Jak Charlton wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 12-10-2009 7:25 PM

I take it when you manually override a component, Windsor then doesn't bother to fill that depenency itself with the default implementation?

(and very very cool btw - something could have used many many times in the past, I see my configuration now pushing back to the container and not to an IConfigurationService)

Michael Sync wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 12-10-2009 9:54 PM

Why "magic" string in new way?

Krzysztof Koźmic wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 12-11-2009 1:39 AM

@Jak

Correct, your override takes priority, and whole operation happens before Windsor even starts looking for dependencies.

@Michael

You want loose coupling, you need magic strings at some point. Since parameter names are just that, I can see no other way.

Rob Reynolds wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 12-11-2009 7:36 AM

This is freakin sweet! Dynamic parameters FTW!

Neil Barnwell wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 12-12-2009 6:41 AM

Excellent stuff - I'm sure it's a common problem everyone has had at one point or another.  Can/How can it be implemented via the xml configuration, though?...  We don't use the fluent interface for component registration.

Krzysztof Koźmic wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 12-13-2009 10:24 AM

@Neil,

As of this moment there's no way of specifying this via XML. I'm not sure how that would look like though. The 'dynamic' part generally implies a method call, and I can't see a nice, concise way of specifying this in XML without introducing some sort of DSL and I don't want to go there.

Do you have any better idea? I would love to implement that if someone comes up with a nice way of doing this.

anon wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 08-23-2012 12:28 AM

you spelled dependency wrong

Hills wrote re: Castle Windsor new feature – dynamic parameters from registration site
on 09-26-2012 7:50 AM

Cool, but DateTime is no primitive. msdn.microsoft.com/.../ms228360%28v=VS.80%29.aspx

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)