C# 如何在WebApi中为属性实现DI?
我重构了一个在Web api中实现基本Http身份验证的属性,使其具有DI,如下所示:C# 如何在WebApi中为属性实现DI?,c#,dependency-injection,attributes,ninject,asp.net-web-api,C#,Dependency Injection,Attributes,Ninject,Asp.net Web Api,我重构了一个在Web api中实现基本Http身份验证的属性,使其具有DI,如下所示: public class BasicHttpAuthAttribute : ActionFilterAttribute { private readonly ILoginManager _manager; public BasicHttpAuthAttribute(ILoginManager manager) { this._
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,所以我可以使用一个构造函数创建一个实例)。重构后的问题是,构建失败,因为当我将过滤器应用于WebApi方法时,它期望在那里有一个参数
在这种情况下,当LoginManager本身在其构造函数中使用ILoginRepository时,如何实现DI?甚至可能吗?最简单的方法是使构造函数不需要参数,而是使用不同的注入形式。具体的实现方式取决于您使用的DI容器。例如,使用Unity,您可以创建一个默认构造函数。创建另一个公共方法(我通常将其称为Initialize以清除),并用[InjectionMethod]属性修饰它。然后,在构造函数内部,只需调用container.build(this);这基本上允许MVC调用它想要的默认构造函数,但是您的InjectionMethod总是作为构建过程的一部分自动调用
对于其他DI容器,也有类似的方法来做同样的事情,但是在不知道您在使用什么的情况下,单元示例是最容易解释的。最容易的选择是使它成为构造函数不需要参数,而是使用不同的注入形式。具体的实现方式取决于您使用的DI容器。例如,使用Unity,您可以创建一个默认构造函数。创建另一个公共方法(我通常将其称为Initialize以清除),并用[InjectionMethod]属性修饰它。然后,在构造函数内部,只需调用container.build(this);这基本上允许MVC调用它想要的默认构造函数,但是您的InjectionMethod总是作为构建过程的一部分自动调用
对于其他DI容器,也有类似的方法来做同样的事情,但是在不知道您在使用什么的情况下,单元示例是最容易解释的。这并不容易,因为在Web API中处理属性的方式与您可能期望的有点不同。首先,它们是在不同的时间点创建的,其次是缓存的 话虽如此,实现DI的最简单方法不是通过构造函数注入,而是在处理时调用您选择的DI框架,然后检索依赖项,即在
onActionExecuting
中:
var s = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IService));
这并不容易,因为在WebAPI中处理属性的方式与您可能期望的有点不同。首先,它们是在不同的时间点创建的,其次是缓存的 话虽如此,实现DI的最简单方法不是通过构造函数注入,而是在处理时调用您选择的DI框架,然后检索依赖项,即在
onActionExecuting
中:
var s = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IService));
您无法控制
BasicHttpAuthAttribute
的实例化,因此无法使用正确的DI
您可以在属性的构造函数中使用ServiceLocator
来提供所需的依赖项,也可以使用一些容器为现有对象提供的build
功能
Unity这样做是为了支持非自己创建的第三方对象的building
对于您的属性,这意味着创建类型为ILoginManager
的公共可写属性,并告诉容器将您的管理器注入该属性
您不必使用
DependencyAttribute
btw来污染您的属性。向容器注册您的属性类型,并提供InjectionProperty(“NameOfPropertyToInject”)
作为该注册的参数。您无法控制BasicHttpAuthAttribute
的实例化,因此无法使用正确的DI
您可以在属性的构造函数中使用ServiceLocator
来提供所需的依赖项,也可以使用一些容器为现有对象提供的build
功能
Unity这样做是为了支持非自己创建的第三方对象的building
对于您的属性,这意味着创建类型为ILoginManager
的公共可写属性,并告诉容器将您的管理器注入该属性
您不必使用DependencyAttribute
btw来污染属性。向容器注册属性类型,并提供InjectionProperty(“NameOfPropertyToInject”)
作为该注册的参数