向 IoC 注册通用 UnitOfWork<> 时出错
Error registering generic UnitOfWork<> with IoC
我的应用程序中的 DbContext 有一个 UnitOfWork 的通用实现,其工作方式如下:
public class UnitOfWork<TContext> : IDisposable, IUnitOfWork<TContext>
where TContext : DbContext
{
private readonly TContext _context;
[..UoW default implementations..]
public void Dispose()
{
_context.Dispose();
}
}
并注册...:
public static class SimpleInjectorWebApiInitializer
{
/// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
InitializeContainer(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
private static void InitializeContainer(Container container)
{
// For instance:
container.Register(typeof(IUnitOfWork<>), typeof(UnitOfWork<>), Lifestyle.Scoped);
container.RegisterWebApiRequest<IBankRepository, BankRepository>();
container.RegisterWebApiRequest<IBankService, BankService>();
}
}
当我尝试注册此类型和其他服务时,我收到这些警告:
-[生活方式不匹配] UnitOfWork<CustomerContext>
(Web API 请求)取决于 CustomerContext(瞬态)。
-[一次性瞬态组件] CustomerContext 注册为瞬态,但实现了 IDisposable。
我的应用程序架构使用默认的 WebAPI 实现:
[RoutePrefix("customer/banks")]
public class BankController : ApiController
{
private readonly IBankService _bankService;
public BankController(IBankService bankService)
{
_bankService = bankService;
}
[Route]
public IEnumerable<BancoModel> Get()
{
var result = _bankService.GetBanks();
[...mappings and return...]
}
}
我已经尝试抑制这些警告:
Registration registration = container.GetRegistration(typeof(IUnitOfWork<>)).Registration;
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent, "Dispose called by application code");
..但我收到 InvalidOperationException。
关于如何注册这个有什么想法吗?
您遇到的问题是您没有为 CustomerContext
添加注册。
因为CustomerContext
有一个默认的构造函数,Simple Injector 能够为你自动装配这个依赖。但是,当 Simple Injector 在第一次调用 GetInstance
时为此进行注册时,容器除了使用默认生活方式注册此服务类型外别无选择。然而,Simple Injector 的默认生活方式是:Transient
.
换句话说,您收到的诊断警告是正确的,因为 CustomerContext
实际上注册为 Transient
。
要解决此问题,请为 CustomerContext
添加一个注册为:
container.Register<CustomerContext>(Lifestyle.Scoped);
你可以去掉警告抑制的配置,因为这些'warnings'是真实存在的问题!
此时实际上有第三个诊断警告可用。您可以阅读 Container-Registered Types
警告 here。此诊断警告通知您对象图中需要的类型不属于您的配置。这是一个信息性警告,因此在验证容器时不会作为异常抛出。信息类别的原因是,对于可以是 Transient
的简单 class,这根本不是问题,并且存在您无法注册所有 class 的有效用例es 在编译时。
但最好在容器中注册所有需要的类型,因为在这种情况下容器完全了解所有 classes,因此能够尽其所能 Verify
你的配置。
这是良好做法的第二个原因是每个 DI 容器都有不同的 'default lifestyle'。简单注入器默认为 Transient
,而其他注入器默认为 Singleton
。如果您以后要交换 DI 容器,您可能会得到一个在运行时失败的应用程序,因为某些组件突然变成 Singleton
.
您在抑制警告时收到 InvalidOperationException
的原因是容器(尚)无法抑制开放泛型类型的警告。在这种情况下这是一件好事,因为你必须来寻求帮助!
如果您成功地抑制了这些警告,您很快就会发现自己在调试奇怪的问题。
因为如果你的 DbContext
是 Transient
会发生什么?
每个 service/commandhandler/queryhandler/etc。依赖于此 DbContext
的将得到一个不同的!!这可能会导致这种情况:
- 你使用 queryhandler/repository 或任何服务从数据库中获取一条记录
- 您将在另一个 service/commandhandler 中用一些新信息更新实体,它对
DbContext
有自己的依赖性,因此是一个不同的实例
- 您可能在另一个 class 中调用
DbContext.SaveChanges()
,同样使用它自己的 DbContext 实例,例如 SaveChangesCommandHandlerDecorator
。因为这个 DbContext
没有跟踪任何更改,所以数据库没有更新。
为了完整起见:
警告是在 CustomerContext
和 UnitOfWork<CustomerContext>
上给出的,因此您应该抑制注册此服务类型时的警告。幸运的是,您没有注册 CustomerContext
,您必须做更多的工作来抑制 UnitOfwork<CustomerContext
!
上的警告
我的应用程序中的 DbContext 有一个 UnitOfWork 的通用实现,其工作方式如下:
public class UnitOfWork<TContext> : IDisposable, IUnitOfWork<TContext>
where TContext : DbContext
{
private readonly TContext _context;
[..UoW default implementations..]
public void Dispose()
{
_context.Dispose();
}
}
并注册...:
public static class SimpleInjectorWebApiInitializer
{
/// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
InitializeContainer(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
private static void InitializeContainer(Container container)
{
// For instance:
container.Register(typeof(IUnitOfWork<>), typeof(UnitOfWork<>), Lifestyle.Scoped);
container.RegisterWebApiRequest<IBankRepository, BankRepository>();
container.RegisterWebApiRequest<IBankService, BankService>();
}
}
当我尝试注册此类型和其他服务时,我收到这些警告:
-[生活方式不匹配] UnitOfWork<CustomerContext>
(Web API 请求)取决于 CustomerContext(瞬态)。
-[一次性瞬态组件] CustomerContext 注册为瞬态,但实现了 IDisposable。
我的应用程序架构使用默认的 WebAPI 实现:
[RoutePrefix("customer/banks")]
public class BankController : ApiController
{
private readonly IBankService _bankService;
public BankController(IBankService bankService)
{
_bankService = bankService;
}
[Route]
public IEnumerable<BancoModel> Get()
{
var result = _bankService.GetBanks();
[...mappings and return...]
}
}
我已经尝试抑制这些警告:
Registration registration = container.GetRegistration(typeof(IUnitOfWork<>)).Registration;
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent, "Dispose called by application code");
..但我收到 InvalidOperationException。
关于如何注册这个有什么想法吗?
您遇到的问题是您没有为 CustomerContext
添加注册。
因为CustomerContext
有一个默认的构造函数,Simple Injector 能够为你自动装配这个依赖。但是,当 Simple Injector 在第一次调用 GetInstance
时为此进行注册时,容器除了使用默认生活方式注册此服务类型外别无选择。然而,Simple Injector 的默认生活方式是:Transient
.
换句话说,您收到的诊断警告是正确的,因为 CustomerContext
实际上注册为 Transient
。
要解决此问题,请为 CustomerContext
添加一个注册为:
container.Register<CustomerContext>(Lifestyle.Scoped);
你可以去掉警告抑制的配置,因为这些'warnings'是真实存在的问题!
此时实际上有第三个诊断警告可用。您可以阅读 Container-Registered Types
警告 here。此诊断警告通知您对象图中需要的类型不属于您的配置。这是一个信息性警告,因此在验证容器时不会作为异常抛出。信息类别的原因是,对于可以是 Transient
的简单 class,这根本不是问题,并且存在您无法注册所有 class 的有效用例es 在编译时。
但最好在容器中注册所有需要的类型,因为在这种情况下容器完全了解所有 classes,因此能够尽其所能 Verify
你的配置。
这是良好做法的第二个原因是每个 DI 容器都有不同的 'default lifestyle'。简单注入器默认为 Transient
,而其他注入器默认为 Singleton
。如果您以后要交换 DI 容器,您可能会得到一个在运行时失败的应用程序,因为某些组件突然变成 Singleton
.
您在抑制警告时收到 InvalidOperationException
的原因是容器(尚)无法抑制开放泛型类型的警告。在这种情况下这是一件好事,因为你必须来寻求帮助!
如果您成功地抑制了这些警告,您很快就会发现自己在调试奇怪的问题。
因为如果你的 DbContext
是 Transient
会发生什么?
每个 service/commandhandler/queryhandler/etc。依赖于此 DbContext
的将得到一个不同的!!这可能会导致这种情况:
- 你使用 queryhandler/repository 或任何服务从数据库中获取一条记录
- 您将在另一个 service/commandhandler 中用一些新信息更新实体,它对
DbContext
有自己的依赖性,因此是一个不同的实例 - 您可能在另一个 class 中调用
DbContext.SaveChanges()
,同样使用它自己的 DbContext 实例,例如SaveChangesCommandHandlerDecorator
。因为这个DbContext
没有跟踪任何更改,所以数据库没有更新。
为了完整起见:
警告是在 CustomerContext
和 UnitOfWork<CustomerContext>
上给出的,因此您应该抑制注册此服务类型时的警告。幸运的是,您没有注册 CustomerContext
,您必须做更多的工作来抑制 UnitOfwork<CustomerContext
!