簡體   English   中英

如何使用Unity基於http請求參數動態地將服務注入到asp.net web api控制器中

[英]How to dynamically inject service into asp.net web api controller based on http request parameter using Unity

我正在使用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);
    }
}

提供者方法arg不必是一個字符串,它可以是一個HttpContextBase或者任何具有您需要的數據的對象來決定返回哪個實現。 然后使用unity注冊提供程序,構造函數將其注入控制器。 最后,在操作中,您使用提供程序來獲取正確的身份驗證服務實現。

如果你真的想避開提供者/工廠模式,我真的不知道在Unity中會是什么樣子。 但是在SimpleInjector(另一個基本上與Unity相同的IoC庫)中,它看起來像這樣:

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));
    }
});

雖然上面應該工作(並且應該有類似的方式來使用Unity),但它只能通過使用靜態HttpContext.Current對象來實現。 我通常不喜歡這種方法,因為它隱藏了組合根中的知識,並且有效地做了與提供者相同的事情。 但這只是我的意見,你可以自由選擇。

如果服務需要自己注射怎么辦?

在根組成期間:

container.Register<HttpGetAuthenticationService>();
container.Register<HttpPostAuthenticationService>();

供應商實施:

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));
        }
    }
}

...再次,這不是Unity的代碼,但我希望Unity可以做同樣的事情,即使API不同。 我同意@Maarten這種事情可以在組合根或應用程序級提供程序中進行。 我傾向於選擇后者而不是前者,可能是因為它對我來說似乎不太“神奇”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM