【问题标题】:How to implement DI for an attribute in WebApi?如何为 WebApi 中的属性实现 DI?
【发布时间】:2012-09-26 21:11:44
【问题描述】:

我重构了一个在 Web api 中实现基本 Http 身份验证的属性,使其具有如下 DI:

 public class BasicHttpAuthAttribute : ActionFilterAttribute
    {
        private readonly ILoginManager _manager;

        public BasicHttpAuthAttribute(ILoginManager manager)
        {
            this._manager = manager;
        }
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (actionContext.Request.Headers.Authorization == null)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                actionContext.Response.Content = new StringContent("Missing Auth-Token");
            }
            else
            {

                var authToken = actionContext.Request.Headers.Authorization.Parameter;
                var decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authToken));

                string userName = decodedToken.Substring(0, decodedToken.IndexOf(":"));
                string password = decodedToken.Substring(decodedToken.IndexOf(":") + 1);


                UserInfo user;


                if (_manager.LoginPasswordMatch(userName, password, out user))
                {
                    var apiUser = new ApiUser(user.UserID);
                    HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(apiUser), new string[]{});

                    base.OnActionExecuting(actionContext);

                }
                else
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                    actionContext.Response.Content = new StringContent("Invalid username or password");
                }



            }
        }
    }

在重构之前,我在 OnActionExecuting 中创建了一个 LoginManager 实例(它本身没有 DI,因此我可以使用 ctor 创建一个实例)。重构后的问题是构建失败,因为当我将过滤器应用于 WebApi 方法时,它期望那里有一个参数。

在这种情况下,当 LoginManager 本身在其构造函数中采用 ILoginRepository 时,我该如何实现 DI?有没有可能?

【问题讨论】:

    标签: c# dependency-injection attributes ninject asp.net-web-api


    【解决方案1】:

    这并不容易,因为 Web API 中处理属性的方式与您所期望的有点不同。首先它们是在不同的时间点创建的,其次它们是缓存的。

    话虽如此,实现 DI 的最简单方法不是通过构造函数进行注入,而是在处理时调用您选择的 DI 框架,然后检索依赖关系,即在您的 onActionExecuting 内部:

    var s = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IService));
    

    【讨论】:

      【解决方案2】:

      最简单的选择是让你的构造函数不需要参数,而是使用不同的注入形式。具体如何操作取决于您使用的 DI 容器。例如,使用 Unity,您可以只创建一个默认构造函数。创建另一个公共方法(为了清楚起见,我通常将其称为 Initialize)并使用 [InjectionMethod] 属性对其进行装饰。然后,在您的构造函数中,只需调用 container.BuildUp(this);这基本上允许 MVC 随意调用默认构造函数,但您的 InjectionMethod 始终作为构造过程的一部分自动调用。

      对于其他 DI 容器也有类似的方法来做同样的事情,但不知道你在使用什么 Unit 示例是最容易解释的。

      【讨论】:

        【解决方案3】:

        您无法控制 BasicHttpAuthAttribute 的实例化,因此您无法使用正确的 DI。

        您可以在属性的构造函数中使用ServiceLocator 来为您提供所需的依赖项,或者您可以使用某些容器为现有对象提供的BuildUp 功能。

        Unity 这样做是为了支持 BuildUp 用于您不是自己创建的第 3 方对象。

        对于您的属性,这意味着创建ILoginManager 类型的公共可写属性并告诉容器将您的管理器注入该属性。

        您不必使用DependencyAttribute btw 来污染您的属性。向容器注册您的属性类型,并提供 InjectionProperty("NameOfThePropertyToInject") 作为该注册的参数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-08-12
          • 1970-01-01
          • 2020-02-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多