我在这里使用 Unity . 但可能我们只需指向一个正确的方向 .
我们知道如何注入接口:
public class AccountController:ApiController
{
private readonly IAccountRepository _repository;
public AccountController(IAccountRepository repository)
{
_repository = repository;
}
}
与 RegisterType
var container = new UnityContainer();
container.RegisterType<IAccountRepository, AccountRepository>(new HierarchicalLifetimeManager());
但在我的 AccountRepository 中,我们有一个注入构造函数的类 .
private readonly ApplicationUserManager _userManager;
public AccountRepository(ApplicationUserManager userManager)
{
_userManager = userManager;
}
因此,在调用ApiController时,我仍然会收到此错误:
尝试创建“AccountController”类型的控制器时发生错误 . 确保控制器具有无参数的公共构造函数 .
堆栈跟踪:
在System.Web.Http.Internal.TypeActivator.Create的System.Linq.Expressions.Expression.New(Type type)中,在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage请求,在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create中键入controllerType,Func`1和activator)(HttpRequestMessage请求,HttpControllerDescriptor controllerDescriptor,类型controllerType)
由于我已经创建了一些工作正常的其他ApiControllers,我想这一定是因为我们的 ApplicationUserManager 无法解决 .
这里 ApplicationUserManager 继承自 UserManager 而不是接口 . 我不能用 container.RegisterType<interface, derived_class>
. 解决问题的正确方法是什么?
这是 ApplicationUserManager :
public class ApplicationUserManager : UserManager<User>
{
public ApplicationUserManager(IdentityContext identityContext)
: base(new UserStore<User>(identityContext))
{
}
}
正如下面的一些评论所示 . 这是 RegisterType 陈述:
var container = new UnityContainer();
container.RegisterType<IAccountRepository, AccountRepository>(new HierarchicalLifetimeManager());
container.RegisterType<ApplicationUserManager, ApplicationUserManager>(new HierarchicalLifetimeManager());
container.RegisterType<IdentityContext, IdentityContext>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
看起来设置 ASP.NET Identity 需要一些特殊的工作 . 我在这里找到一个链接:Configure Unity DI for ASP.NET Identity . 但到目前为止,我仍然无法使其发挥作用 .
3 回答
问题是你的AccountController类没有无参数构造函数,你在堆栈跟踪 has no idea how to instantiate it 中看到的DefaultHttpControllerActivator .
幸运的是,ASP.NET WebAPI具有将控制器实例化任务委派给DI容器的内置方式 . 本文完全涵盖您的用例,甚至还有下载源代码:https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection
为了防止链接腐烂我已经存档下面的文章(尽可能地从html转换格式,随意改进它):
ASP.NET Web API 2中的
依赖注入
作者:Mike Wasson
在本文中
本教程中使用的软件版本
什么是依赖注入?
Web API依赖关系解析器
使用Unity容器的依赖项解析
配置依赖关系解析器
依赖范围和控制器生命周期
Download Completed Project
什么是依赖注入?
依赖项是另一个对象所需的任何对象 . 例如,它举例说明了一下 . 首先,我们将定义一个域模型:
C#
这是一个简单的存储库类,使用Entity Framework将项目存储在数据库中 .
C#
现在让我们定义一个支持
Product
实体的GET请求的Web API控制器 . (为了简单起见,我省略了POST和其他方法 . )这是第一次尝试:C#
请注意,控制器类依赖于
ProductRepository
,我们让控制器创建ProductRepository
实例 . 但是,出于几个原因,以这种方式对依赖项进行硬编码是一个坏主意 .如果要将
ProductRepository
替换为其他实现,还需要修改控制器类 .如果
ProductRepository
具有依赖项,则必须在控制器内配置它们 . 对于具有多个控制器的大型项目,您的配置代码将分散在整个项目中 .单元测试很难,因为控制器是硬编码的,用于查询数据库 . 对于单元测试,您应该使用模拟或存根存储库,这在当前设计中是不可能的 .
我们可以通过将存储库注入控制器来解决这些问题 . 首先,将
ProductRepository
类重构为一个接口:C#
然后提供
IProductRepository
作为构造函数参数:C#
此示例使用构造函数注入 . 您还可以使用setter注入,通过setter方法或属性设置依赖项 .
但是现在有一个问题,因为你的应用程序对
IProductRepository
一无所知 . 这是Web API依赖项解析器的用武之地 .Web API依赖关系解析器
Web API定义了用于解析依赖关系的 IDependencyResolver 接口 . 这是界面的定义:
C#
IDependencyScope 接口有两种方法:
GetService 创建一个类型的实例 .
GetServices 创建指定类型的对象集合 .
IDependencyResolver 方法继承 IDependencyScope 并添加 BeginScope 方法 . 我将在本教程后面讨论范围 .
当Web API创建控制器实例时,它首先调用 IDependencyResolver.GetService ,传入控制器类型 . 您可以使用此扩展性挂钩来创建控制器,进行解析任何依赖 . 如果 GetService 返回null,则Web API在控制器类上查找无参数构造函数 .
使用Unity容器的依赖项解析
虽然您可以从头开始编写完整的 IDependencyResolver 实现,但该接口实际上是作为Web API和现有IoC容器之间的桥梁而设计的 .
IoC容器是负责管理依赖关系的软件组件 . 您使用容器注册类型,然后使用容器创建对象 . 容器自动计算出依赖关系 . 许多IoC容器还允许您控制对象生命周期和范围等内容 .
注意
“IoC”代表“控制反转”,这是框架调用应用程序代码的一般模式 . IoC容器为您构造对象,它“反转”通常的控制流 .
在本教程中,我们将使用Microsoft模式和实践中的Unity . (其他受欢迎的库包括Castle Windsor,Spring.Net,Autofac,Ninject和StructureMap . )您可以使用NuGet Package Manager来安装Unity . 从Visual Studio中的 Tools 菜单中,选择 Library Package Manager ,然后选择 Package Manager Console . 在“程序包管理器控制台”窗口中,键入以下命令:
安慰
这是包装Unity容器的 IDependencyResolver 的实现 .
C#
注意
如果 GetService 方法无法解析类型,则应返回 null . 如果 GetServices 方法无法解析类型,则应返回空集合对象 . 不要为未知类型抛出异常 .
配置依赖关系解析器
在全局 HttpConfiguration 对象的 DependencyResolver 属性上设置依赖项解析程序 .
以下代码在Unity中注册
IProductRepository
接口,然后创建UnityResolver
.C#
依赖范围和控制器生命周期
根据请求创建控制器 . 为了管理对象的生命周期, IDependencyResolver 使用了范围的概念 .
附加到 HttpConfiguration 对象的依赖项解析程序具有全局范围 . 当Web API创建控制器时,它会调用 BeginScope . 此方法返回表示子范围的 IDependencyScope .
然后,Web API在子作用域上调用 GetService 来创建控制器 . 请求完成后,Web API会在子范围上调用 Dispose . 使用 Dispose 方法处理控制器的依赖项 .
如何实现 BeginScope 取决于IoC容器 . 对于Unity,范围对应于子容器:
C#
你不需要这两行,因为Unity会为你解决它 .
IdentityContext
的构造函数是什么样的?它很可能具有您尚未注册的依赖关系 . 如果它有多个构造函数,Unity将选择具有最多参数的构造函数 .如果您想要一个非默认的生命周期管理器,您仍然需要使用unity注册这些类型 . 但是,Unity使用不同的语法,只有一个通用参数来注册具体类型(而不是类型映射):
显然我不能从这里尝试代码,但看看是否能解决你的问题 .