8

I have 2 implementations of the same interface and want to use implementation1 if the user is logged in or implementation2 if the user is not logged in. How can I configure this with castle windsor?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Mark
  • 81
  • 2

2 Answers2

8

You could add a handler selector, which would be able to select between available implementations depending on e.g. whether Thread.CurrentPrincipal was set (or HttpContext.Current.Request.IsAuthenticated in ASP.NET/MVC if I remember correctly).

The handler selector would probably look somewhat like this:

public class MyAuthHandlerSelector : IHandlerSelector
{
    public bool HasOpinionAbout(string key, Type service)
    {
        return service == typeof(ITheServiceICareAbout);
    }

    public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
    {
        return IsAuthenticated 
            ? FindHandlerForAuthenticatedUser(handlers)
            : FindGuestHandler(handlers);
    }

    bool IsAuthenticated
    {
        get { return Thread.CurrentPrincipal != null; } 
    }
    // ....
}

Only downside of handler selectors is that they're not pulled from the container - i.e. they're added as an instance to the container at registration time, so they don't get to have dependencies injected, lifestyle managed, etc., but there are ways to mitigate that - take a look at F.T.Windsor if you're interested in seeing how that can be done.

mookid8000
  • 18,258
  • 2
  • 39
  • 63
  • 1
    wondering if with 3.0 version anything changed - I mean if it is still needed external facility. – Giedrius Nov 16 '12 at 13:55
  • The "handler selector" link is obsolete. The actual one is: https://github.com/castleproject/Windsor/blob/master/docs/handler-selectors.md – cly Mar 27 '23 at 08:49
1

One way to solve this would be, Register the service with key and then resolve as you need.

public interface ISample
{
    int Calculate(int a, int b);
}

class SampleB : ISample
{
    public int Calculate(int a, int b)
    {
        return a + b + 10;
    }
}

class SampleA : ISample
{
    public int Calculate(int a, int b)
    {
        return a + b;
    }
}

The registration:

        container.Register(Component.For<ISample>().ImplementedBy<SampleA>().Named("SampleA").LifeStyle.Transient);
        container.Register(Component.For<ISample>().ImplementedBy<SampleB>().Named("SampleB").LifeStyle.Transient);

// Resolve when SampleA needed.

var sampleA = container.Resolve<ISample>("SampleA");

// Resolve when SampleB needed.

var sampleB = container.Resolve<ISample>("SampleB");
Shuhel Ahmed
  • 963
  • 8
  • 14
  • There is no way windsor will know user is logged in or not unless you alter/extend it's internal implementation. There can be a Decider class in between which will take 'log in factor' in account and give the desired implementation. – Shuhel Ahmed Sep 21 '11 at 20:20
  • Windsor *does* have mechanisms for this (see mookid's answer), it's not necessary to alter its internal implementation at all. – Mauricio Scheffer Sep 21 '11 at 20:46
  • Thanks, I meant to say extend not 'alter'. +1 for mookids's answeer. – Shuhel Ahmed Sep 21 '11 at 21:34
  • 1
    As long as [Static service locator is not good idea](http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx), you can use this solution only if you have access to container - and usually you don't. – Giedrius Nov 16 '12 at 13:52