C# 如何使用Unity基于http请求参数将服务动态注入asp.net web api控制器

C# 如何使用Unity基于http请求参数将服务动态注入asp.net web api控制器,c#,asp.net,asp.net-web-api,unity-container,C#,Asp.net,Asp.net Web Api,Unity Container,我正在使用Unity将服务实例注入ASP.NET Web API控制器的构造函数中 在下面的代码中,我希望根据发出的http请求注入IAuthenticationService的不同实现 这可能吗 public class AuthenticateController : ApiController { public AuthenticateController(IAuthenticationService authenticationService) { } 简而言之

我正在使用Unity将服务实例注入ASP.NET Web API控制器的构造函数中

在下面的代码中,我希望根据发出的http请求注入IAuthenticationService的不同实现

这可能吗

public class AuthenticateController : ApiController
{
    public AuthenticateController(IAuthenticationService authenticationService)
    {
    }

简而言之,这是可能的,但我不建议这样做,因为IoC容器必须静态地使用
HttpContext.Current
。我推荐的模式更像这样:

public interface IProvideAuthenticationService
{
    IAuthenticationService GetService(string requestMethod);
}

public class AuthenticationServiceProvider : IProvideAuthenticationService
{
    public IAuthenticationService GetService(string requestMethod)
    {
        switch (requestMethod)
        {
            case "GET":
                return new HttpGetAuthenticationService();
            case "POST":
                return new HttpPostAuthenticationService();
            default:
                throw new NotSupportedException(string.Format(
                    "Cannot find AuthenticationService for requestMethod '{0}'",
                        requestMethod));
        }
    }
}

public class AuthenticateController : ApiController
{
    private readonly IProvideAuthenticationService _authenticationServiceProvider;

    public AuthenticateController(IProvideAuthenticationService authenticationServiceProvider)
    {
        _authenticationServiceProvider = authenticationServiceProvider;
    }

    [HttpGet]
    public ActionResult Get()
    {
        IAuthenticationService authService = _authenticationServiceProvider.GetService(HttpContext.Request.HttpMethod);
    }

    [HttpPost]
    public ActionResult Post()
    {
        IAuthenticationService authService = _authenticationServiceProvider.GetService(HttpContext.Request.HttpMethod);
    }
}
container.Register<IAuthenticationService>(() => {
    string requestMethod = HttpContext.Current.Request.HttpMethod;
    switch (requestMethod)
    {
        case "GET":
            return new HttpGetAuthenticationService();
        case "POST":
            return new HttpPostAuthenticationService();
        default:
            throw new NotSupportedException(string.Format("Cannot find AuthenticationService for requestMethod '{0}'", requestMethod));
    }
});
provider方法arg不必是字符串,它可以是
HttpContextBase
或任何包含决定返回哪个实现所需数据的对象。然后向unity注册提供程序,并将其注入控制器。最后,在操作中,使用提供程序获得正确的身份验证服务实现

如果您真的想避免提供者/工厂模式,我真的不知道Unity中会是什么样子。但是在SimpleInjector(另一个IoC库,基本上与Unity做相同的事情)中,它看起来是这样的:

public interface IProvideAuthenticationService
{
    IAuthenticationService GetService(string requestMethod);
}

public class AuthenticationServiceProvider : IProvideAuthenticationService
{
    public IAuthenticationService GetService(string requestMethod)
    {
        switch (requestMethod)
        {
            case "GET":
                return new HttpGetAuthenticationService();
            case "POST":
                return new HttpPostAuthenticationService();
            default:
                throw new NotSupportedException(string.Format(
                    "Cannot find AuthenticationService for requestMethod '{0}'",
                        requestMethod));
        }
    }
}

public class AuthenticateController : ApiController
{
    private readonly IProvideAuthenticationService _authenticationServiceProvider;

    public AuthenticateController(IProvideAuthenticationService authenticationServiceProvider)
    {
        _authenticationServiceProvider = authenticationServiceProvider;
    }

    [HttpGet]
    public ActionResult Get()
    {
        IAuthenticationService authService = _authenticationServiceProvider.GetService(HttpContext.Request.HttpMethod);
    }

    [HttpPost]
    public ActionResult Post()
    {
        IAuthenticationService authService = _authenticationServiceProvider.GetService(HttpContext.Request.HttpMethod);
    }
}
container.Register<IAuthenticationService>(() => {
    string requestMethod = HttpContext.Current.Request.HttpMethod;
    switch (requestMethod)
    {
        case "GET":
            return new HttpGetAuthenticationService();
        case "POST":
            return new HttpPostAuthenticationService();
        default:
            throw new NotSupportedException(string.Format("Cannot find AuthenticationService for requestMethod '{0}'", requestMethod));
    }
});
提供程序实现:

public class AuthenticationServiceProvider : IProvideAuthenticationService
{
    private readonly Container _container;

    public AuthenticationServiceProvider(Container container)
    {
        _container = container;
    }

    public IAuthenticationService GetService(string requestMethod)
    {
        switch (requestMethod)
        {
            case "GET":
                return _container.GetInstance<HttpGetAuthenticationService>();
            case "POST":
                return _container.GetInstance<HttpPostAuthenticationService>();
            default:
                throw new NotSupportedException(string.Format(
                    "Cannot find AuthenticationService for requestMethod '{0}'",
                        requestMethod));
        }
    }
}
公共类AuthenticationServiceProvider:IProvideAuthenticationService
{
私有只读容器_容器;
公共AuthenticationServiceProvider(容器)
{
_容器=容器;
}
公共IAAuthenticationService GetService(字符串请求方法)
{
开关(请求方法)
{
案例“GET”:
返回_container.GetInstance();
案例“职位”:
返回_container.GetInstance();
违约:
抛出新的NotSupportedException(string.Format(
找不到requestMethod“{0}”的AuthenticationService,
(方法);
}
}
}

…同样,这不是Unity的代码,但我希望Unity可以做同样的事情,即使API不同。我同意@Maarten的观点,这种东西可以放在合成根目录中,也可以放在应用程序级提供程序中。与前者相比,我更喜欢后者,可能是因为它对我来说似乎不那么“神奇”。

在这种情况下,听起来你需要使用Factory。我同意@Michael,您希望注入某种工厂或提供程序,它将接受请求类型作为方法参数,并返回IAAuthenticationService的预期实现。这很有意义。谢谢大家!@BrianMcCarthy自从你接受答案后,我已经更新了答案,以防你想重读。如果服务本身需要注射怎么办?那么更新就不能像这样工作了,你需要容器。这意味着此工厂/提供程序是合成根的一部分。您始终可以创建一个单独的类,该类是使用容器的组合根的一部分,而不是引导程序中的lambda类。@Maarten如果服务实现也具有依赖性,则提供程序可以对容器具有依赖性,并执行类似于
\u container.GetInstance()