我的应用程序中有一个针对我的DbContexts的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(Transient)。
- [Disposable Transient Component] CustomerContext注册为transient,但实现了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。
有关如何注册的任何想法?
答案 0 :(得分:6)
您遇到的问题是您没有为CustomerContext
添加注册。
因为CustomerContext
具有默认构造函数,所以Simple Injector能够为您自动装配此依赖项。但是当Simple Injector在第一次调用GetInstance
时对此进行注册时,容器除了使用默认生活方式注册此servicetype之外别无选择。然而,Simple Injector的默认生活方式是:Transient
。
换句话说,您收到的诊断警告是正确的,因为CustomerContext
实际上已注册为Transient
。
要解决此问题,请将CustomerContext
的注册添加为:
container.Register<CustomerContext>(Lifestyle.Scoped);
您可以删除警告抑制的配置,因为这些“警告”是实际问题!
此时实际上有第三个诊断警告。您可以阅读有关Container-Registered Types
警告here的信息。此诊断警告通知您对象图中需要的类型不属于您的配置。这是一个信息警告,因此在验证容器时不会抛出异常。信息类别的原因是,对于一个可以Transient
的简单类,这根本不是问题,并且存在无法在编译时注册所有类的有效用例。
但最好在容器中注册所有需要的类型,因为容器在这种情况下完全了解所有类,从而能够尽最大努力Verify
您的配置。< / p>
这是良好做法的第二个原因是因为每个DI容器都有不同的“默认生活方式”。 Simple Injector默认为Transient
,而其他默认值为Singleton
。如果您稍后交换DI容器,最终可能会导致应用程序在运行时失败,因为某个组件突然变为Singleton
。
您收到InvalidOperationException
抑制警告的原因是容器未能(还)能够抑制打开的泛型类型的警告。在这种情况下,这是件好事,因为你必须来寻求帮助!
如果您成功地抑制了这些警告,您很快就会发现自己正在调试奇怪的问题。
因为如果您的DbContext
是Transient
会发生什么?
每个service / commandhandler / queryhandler / etc.依赖于此DbContext
的人会得到一个不同的!这可能导致这种情况:
DbContext
的依赖关系,因而是另一个实例DbContext.SaveChanges()
,再次使用自己的DbContext实例,SaveChangesCommandHandlerDecorator
进行检查。由于此DbContext
未跟踪任何更改,因此数据库不会更新。 为了完整起见:
警告在CustomerContext
和UnitOfWork<CustomerContext>
上给出,因此您应该已经抑制了此servicetypes注册的警告。幸运的是,您没有CustomerContext
的注册,而且您需要做一些工作来抑制UnitOfwork<CustomerContext
上的警告!