1

我重构了一个在 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 方法时,它期望那里有一个参数。

在这种情况下,我如何实现 DI,因为 LoginManager 本身在其构造函数中采用 ILoginRepository?甚至可能吗?

4

3 回答 3

2

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

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

var s = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IService));
于 2012-09-26T13:08:26.133 回答
1

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

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

于 2012-09-26T13:01:27.603 回答
1

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

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

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

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

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

于 2012-09-26T13:11:44.937 回答