具有多次注射的DbContexts的生活方式错误(例如EntityRepository< TEntity>和FooService) [英] Lifestyle errors for DbContexts with multiple injections (ex. EntityRepository<TEntity> and FooService)

查看:190
本文介绍了具有多次注射的DbContexts的生活方式错误(例如EntityRepository< TEntity>和FooService)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于冗长的帖子我很抱歉。请随时跳到底部的问题



上下文是一个ASP.NET系统。其数据层基于实体框架,简单注入器便于依赖注入。



目前只有一个 DbContext 它在命令/查询式商业服务层以及基本存储库中被多个类消耗。



之前



  //上下文自映射
container.Register< SomeContext>(Lifestyle.Scoped);
//存储库被单独映射,每个都期望SomeContext
container.Register< IRepository< Foo>,FooRepository>(Lifestyle.Scoped);
container.Register< IRepository< Bar>,BarRepository>(Lifestyle.Scoped);





IRepository< T> 被一个基类替换,期望 DbContext 的基类(参考):

  // EntityRepository.cs 
public class EntityRepository< TEntity> :IEntityRepository< TEntity>其中TEntity:class
{
private readonly DbContext _context;
private readonly DbSet< TEntity> _dbSet;

public EntityRepository(DbContext context){
_context = context;
_dbSet = context.Set< TEntity>();
}
}

//空白的映射呼叫,需要显式映射DbContext
container.Register< DbContext,SomeContext>(Lifestyle.Scoped);
container.Register(typeof(IEntityRepository>),typeof(EntityRepository&)),Lifestyle.Scoped);



问题



映射DbContext便于存储库但是直接使用SomeContext失败:

  // [Lifestyle Mismatch] FooService(Web Request)取决于SomeContext(Transient)。 
// [Short Circuited Dependency] FooService可能会错误地依赖于未注册的类型SomeContext(Transient)而不是DbContext(Web Request)。
// [Ambiguous Lifestyles] DbContext(Web Request)的注册映射到与SomeContext(Transient)注册相同的实现(SomeContext),但注册映射到不同的生活方式。这将导致每个注册机构解决一个不同的实例。



尝试解决方案:



添加SomeContext的旧自我映射回来:

  container.Register< SomeContext>(Lifestyle.Scoped); 
container.Register< DbContext,SomeContext>(Lifestyle.Scoped);
container.Register(typeof(IEntityRepository>),typeof(EntityRepository&)),Lifestyle.Scoped);

这会导致新的(更好的)错误:

  // [Torn Lifestyle] SomeContext的注册映射到与DbContext的注册相同的实现和生活方式。他们都映射到SomeContext(Web请求)。这将导致每个注册解析到不同的实例:每个注册将在单个Web请求期间具有自己的实例。 






问题



如何指示简单注入器:


  1. 在要求SomeContext
  2. $ b $时提供SomeContext b
  3. 当EntityRepository询问DbContext时提供SomeContext


解决方案

简单喷射器v4,破旧的生活方式应该是过去的事情。简单的注射器将自动防止您的生活疲惫。以下注册将会成功:

  container.Register< SomeContext>(Lifestyle.Scoped); 
container.Register< DbContext,SomeContext>(Lifestyle.Scoped);

您可以在关于撕裂生活方式的文档。简而言之,您必须创建一个注册实例,并为 DbContext SomeContext 如下:

  var registration = Lifestyle.Scoped.CreateRegistration< SomeContext>(container) ; 

container.AddRegistration(typeof(SomeContext),注册);
container.AddRegistration(typeof(DbContext),注册);

这样可以防止被破坏的生活方式,并确保您有一个 SomeContext 实例,而不是两个。


I apologize for the lengthy post. Feel free to skip to Question at the bottom.

The context is an ASP.NET system. Its data layer is based on Entity Framework, and dependency injection is facilitated by Simple Injector.

There is currently only one DbContext and it is consumed by multiple classes in a command/query-like business services layer as well as basic repositories.

Before

// Context self mapped 
container.Register<SomeContext>(Lifestyle.Scoped);
// Repositories were individually mapped, each expect SomeContext
container.Register<IRepository<Foo>, FooRepository>(Lifestyle.Scoped);
container.Register<IRepository<Bar>, BarRepository>(Lifestyle.Scoped);

After

IRepository<T> was replaced by a base class that expects DbContext to be injected (reference):

// EntityRepository.cs
public class EntityRepository<TEntity> : IEntityRepository<TEntity> where TEntity : class
{
    private readonly DbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    public EntityRepository(DbContext context) {
        _context = context;
        _dbSet = context.Set<TEntity>();
    }
}

// Blanked mapped respositories, requiring DbContext to be explicitly mapped
container.Register<DbContext, SomeContext>(Lifestyle.Scoped);
container.Register(typeof(IEntityRepository<>), typeof(EntityRepository<>), Lifestyle.Scoped);

Problem

Mapping DbContext facilitates the repositories, but direct usage of SomeContext fails:

//[Lifestyle Mismatch] FooService (Web Request) depends on SomeContext (Transient).
//[Short Circuited Dependency] FooService might incorrectly depend on an unregistered type SomeContext (Transient) instead of DbContext (Web Request).
//[Ambiguous Lifestyles] The registration for DbContext (Web Request) maps to the same implementation (SomeContext) as the registration for SomeContext (Transient) does, but the registration maps to a different lifestyle. This will cause each regisration to resolve to a different instance.

Attempted Solution:

Added SomeContext's old self-mapping back:

container.Register<SomeContext>(Lifestyle.Scoped);
container.Register<DbContext, SomeContext>(Lifestyle.Scoped);
container.Register(typeof(IEntityRepository<>), typeof(EntityRepository<>), Lifestyle.Scoped);

This resulting in new (better?) errors:

//[Torn Lifestyle] The registration for SomeContext maps to the same implementation and lifestyle as the registration for DbContext does. They both map to SomeContext (Web Request). This will cause each registration to resolve to a different instance: each registration will have its own instance during a single Web Request.


Question

How does one instruct Simple Injector to:

  1. Provide a SomeContext when asked for SomeContext
  2. Provide a SomeContext when an EntityRepository asks for a DbContext

解决方案

With the introduction of Simple Injector v4, Torn lifestyles should be a thing from the past. Simple Injector injector will automatically prevent torn lifestyles for you. The following registration will do the trick:

container.Register<SomeContext>(Lifestyle.Scoped);
container.Register<DbContext, SomeContext>(Lifestyle.Scoped);

You can find the answer to this in the documentation about Torn lifestyles. In short, you will have to create one Registration instance and add that registation for both DbContext and SomeContext as follows:

var registration = Lifestyle.Scoped.CreateRegistration<SomeContext>(container);

container.AddRegistration(typeof(SomeContext), registration);
container.AddRegistration(typeof(DbContext), registration);

This prevents the torn lifestyle and ensures that you have a single SomeContext instance for the duration of the request, instead of two.

这篇关于具有多次注射的DbContexts的生活方式错误(例如EntityRepository&lt; TEntity&gt;和FooService)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆