使用城堡windsor的ASP.NET MVC中的条件依赖性解析

Che*_*iya 1 asp.net-mvc dependency-injection castle-windsor inversion-of-control

我试图在我们的代码中解决这种情况,我需要在运行时根据特定条件解决依赖关系,例如是否存在某些查询字符串值.

假设我有一个控制器AuthenticationController,我有两种风格的身份验证服务.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用城堡windsor实现了IoC和DI.

我正在Castle容器中为IAuthenticationService注册ProviderBasedAuthenticationService和ThirdPartyAuthenticationService.

当前Castle解析IAuthenticationService时解析第一个注册类型的对象.

我希望根据请求URL或路由数据中作为查询字符串一部分的特定值来解析适当类型的IAuthenticationService.

我发现这可以通过Microsoft UnityContainer以某种方式完成,但我不知道如何在Castle Windsor中实现这一点.(我现在无法将容器更改为Microsoft UnityContainer).

如果有人能帮助我或者提供一些方向,我将不胜感激.

谢谢和问候,Chetan Ranpariya

quj*_*jck 6

您可以使用工厂方法执行此操作.这是一个例子:

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>();
}
Run Code Online (Sandbox Code Playgroud)

并通过2个单元测试来证明解决方案

[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);
}
Run Code Online (Sandbox Code Playgroud)