1

I am trying to solve this case in our code where I need to resolve the dependency at runtime based on a specific condition, such as if certain query string value exist or not.

Let say I have a controller AuthenticationController and I have authentication service having two flavours of it.

public class AuthenticationController
{
    private readonly IAuthenticationService authenticationService;

    public AuthenticationController(IAuthenticationService authenticationService)
    {
        this.authenticationService = authenticationService;
    }

    public ActionResult LogOn(LogOnModel model)
    {
        var isAuthenticated = authenticationService.AuthenticatUser(model.UserName, model.Password);
    }
}

public interface IAuthenticationService
{
    bool AuthenticatUser(string userName, string password);
}

public class ProviderBasedAuthenticationService : IAuthenticationService
{
    public bool AuthenticatUser(string userName, string password)
    {
        // Authentication using provider;
        return true;
    }
}


public class ThirdPartyAuthenticationService : IAuthenticationService
{
    public bool AuthenticatUser(string userName, string password)
    {
        // Authentication using third party;
        return true;
    }
}

I have implemented IoC and DI using castle windsor.

I am registering both ProviderBasedAuthenticationService and ThirdPartyAuthenticationService for IAuthenticationService in Castle container.

Currently Castle resolves object of the first registered type when resolving IAuthenticationService.

I wish to resolve appropriate type of IAuthenticationService depending on certain value coming as part of query string in the request URL or route data.

I found that this can be somehow done using Microsoft UnityContainer but I am not sure how to achieve this in Castle Windsor. (I can not change my container now to Microsoft UnityContainer).

It would be much appreciated if anyone can help me on this or provide some direction around this.

Thanks and regards, Chetan Ranpariya

1 Answer 1

6

You can do this with a factory method. Here's an example:

private WindsorContainer ContainerFactory()
{
    var container = new WindsorContainer();
    container.Register(
        Component.For<ProviderBasedAuthenticationService>()
            .LifeStyle.Transient,
        Component.For<ThirdPartyAuthenticationService>()
            .LifeStyle.Transient,
        Component.For<AuthenticationController>()
            .LifeStyle.Transient,
        Component.For<IAuthenticationService>()
            .UsingFactoryMethod((k, c) => this.AuthenticationServiceFactory(k)));

    return container;
}

private IAuthenticationService AuthenticationServiceFactory(IKernel kernel)
{
    return HttpContext.Current != null &&
           HttpContext.Current.Request != null &&
           HttpContext.Current.Request.QueryString["SomeKey"] != null
        ? (IAuthenticationService)kernel.Resolve<ThirdPartyAuthenticationService>()
        : (IAuthenticationService)kernel.Resolve<ProviderBasedAuthenticationService>();
}

And 2 unit tests to prove the solution

[Fact]
public void Resolve_WithoutTheRequiredQueryString_ReturnsProviderBasedAuthenticationService()
{
    var container = this.ContainerFactory();

    var result = container.Resolve<AuthenticationController>();

    Assert.IsType<ProviderBasedAuthenticationService>(result.authenticationService);
}

[Fact]
public void Resolve_WithTheRequiredQueryString_ReturnsThirdPartyAuthenticationService()
{
    var container = this.ContainerFactory();
    HttpContext.Current = new HttpContext(
        new HttpRequest("", "http://localhost", "SomeKey=Value"),
        new HttpResponse(null));

    var result = container.Resolve<AuthenticationController>();

    Assert.IsType<ThirdPartyAuthenticationService>(result.authenticationService);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Hi qujk, you nailed it. I some how could not think of having separate factory method but I was trying to do it using inline dynamic method. The approach you provide should surely work. Thank you. - Chetan Ranpariya

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.