views:

58

answers:

3

I have a reporting MVC application that uses Castle Windsor.

On application start up (in global.asax) all of the types are registered and then each subsequent request to the application resolves the relevant report type and windsor automatically handles the dependencies.

I need to switch one of the dependant types for another depending on a parameter passed in on the request.

How can I achieve this?

I have registered a factory method with windsor to handle the resolution of the switchable types but as this is registered on application start how can I pass a parameter to the factory method when the parameter is only available on a later request?

If I try registering the factory for each request it works on the first request but then complains on all subsequent requests that the factory is already registered. Unregistering the factory after each request doesnt sound like the right thing to be doing.

+1  A: 

When you need to resolve types at runtime, the normal solution is to inject a factory that can make the decision at the appropriate time:

public class ReportFactory: IReportFactory {
    IReport CreateReport(bool useDefault) {
        if (useDefault) {
            return new DefaultReport();
        } else {
            return new UnusualReport();
        }
    }
}

Classes that previously required an IReport should demand an IReportFactory instead.

Jeff Sternal
Thanks Jeff, I think the problem here is that I would need to pass my parameter down through many objects to the point where the factory was injected in order for it to make the decision about which type to use. I was hoping to avoid that.
Si Keep
@Si - without knowing the particulars of your case, it sounds like it might be worth changing the design to bring the (hypothetical) factory closer to the object that determines the factory's product. At the very least, keeping the parameter in the same call chain as the factory method invocation should make the code easier to follow and maintain.
Jeff Sternal
Thats not a bad idea Jeff, I could then pass the factory created object around instead of the parameter.
Si Keep
+1  A: 

You definitely don't want to go modifying your container on a per-request basis. That's a recipe for disaster.

You've got two options. The first is to use HttpContext.Current inside the factory method.

IWhatever CreateWhatever() {
     if (HttpContext.Current.Request["parameter"] == "value-for-other-whatever")
       return new FirstWhatever();

     return DefaultWhatever();
}

The other (better) option would be to inject a factory type that resolves the correct implementation, rather than having the container do it for you.

public class WhateverFactory : IWhateverFactory {
     public IWhatever GetWhatever(string parameter) {
         if(parameter == "value for other whatever")
            return new OtherWhatever();

         return new DefaultWhatever();
     }
}

Your controller would then take an instance of the factory, and would let the factory make the decision of which type to instantiate.

Nick Aceves
+1  A: 

Use TypedFactoryFacility for your factory.

You can take two appraoches:

With default convention, if you have a component registered with name "CustomFoo" the 2nd method would resolve that component, whereas the first one would get the default one.

public interface IFooFactory
{
   IFoo GetFoo(...arguments);
   IFoo GetCustomFoo(..arguments);

   void ReleaseFoo(IFoo foo);
}
Krzysztof Koźmic