【问题标题】:How do I set my project to create the entity-framework context per http request?如何设置我的项目以根据 http 请求创建实体框架上下文?
【发布时间】:2014-06-14 03:42:24
【问题描述】:

我正在使用 EF6 开发 C# MVC5 项目。目前,上下文是在 UnityConfig.cs 类中创建的,该类是从 Global 中的 Application_Start() 调用的。请看下面的一些使用 UnityConfig 类:

public static void RegisterComponents()
{
   var container = new UnityContainer();
   BlogSite.Domain.BlogSiteModelContainer context = new Domain.BlogSiteModelContainer();
   container.RegisterType<IBlogRepository, BlogRepository>(new InjectionConstructor(context));
}

这样做的问题是数据库可能会直接更新,因此 EF 上下文会变得不一致。所以我需要更改它,以便在每次有新的 http 请求时重新加载它。

我发现 PerRequestLifetimeManager 可能是解决这个问题的方法,但是我找不到一个很好的例子来说明我应该如何使用它。

我应该如何实现这个?还是有更好的办法?


所以我尝试了一些事情,但仍然没有成功。我意识到我可以使用 container.RegisterType() 方法添加生命周期管理器,但我认为这只适用于存储库而不适用于实体框架上下文。

例如

container.RegisterType<IBlogRepository, BlogRepository>(new PerRequestLifetimeManager(), new InjectionConstructor(context));

我仍然不确定如何设置上下文的生命周期。我意识到我可能需要重新格式化代码,但我在任何地方都找不到这种情况的示例。


我一直在做更多的研究,并研究了创建一个工作单元以在其中创建上下文并将其传递给存储库的想法。不确定这是否是最好的前进方式,但它似乎是一种可行的方式。对此有什么想法吗?

【问题讨论】:

  • 您的 dbcontext 不仅会变得陈旧,而且会膨胀,因为它缓存了越来越多来自先前交互的垃圾。它并不意味着长寿。通常,我会尝试通过在所需范围内使用using 语句内联来将上下文的生命周期保持在绝对最小值。不过,我不知道这将如何与您的 DI 一起使用。
  • 上述方法或类似方法需要以一种可以通过每个请求调用的方式公开,例如 ReRegisterComponents()。但是,这种方式否定了di的一些优点。
  • 你不能在你的控制器基类中实例化你的上下文吗?如果不进行过度设计,这难道不能解决您的问题吗?
  • 我应该提一下,我的单元测试仍然需要模拟存储库。
  • 你的问题是你在你的 DI 框架之外更新你的上下文,所以它总是注入同一个实例。你需要配置你的 DI 来实例化你的上下文。

标签: c# dependency-injection unity-container asp.net-mvc-5 entity-framework-6


【解决方案1】:

找到了解决办法。我需要创建一个 UnitOfWork 类,我在其中创建了上下文和存储库。然后我使用 Unity 将 UnitOfWork 类注入到具有 PerRequestLifetimeManager 生命周期管理器的控制器中。

所以我的 UnitOfWork 类(存储在我的 DAL 项目中)是:

public class UnitOfWork : IDisposable
{
    private static BlogSite.Domain.BlogSiteModelContainer context;
    public IBlogRepository blogRepository;

    public UnitOfWork()
    {
        context = new BlogSite.Domain.BlogSiteModelContainer();;
        blogRepository = new BlogRepository(context);
    }

    public void Save()
    {
        context.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

我只是在我的 UnityConfig 类中注册了这个:

container.RegisterInstance<UnitOfWork>(new UnitOfWork(), new PerRequestLifetimeManager());

然后,在我的控制器中,我只需对构造函数进行一些小改动,以便它们接受 UnitOfWork 而不是存储库。

例如

IBlogRepository blogRepo;

public BlogController(UnitOfWork unitOfWork)
{
   blogRepo = unitOfWork.blogRepository;
}

【讨论】:

  • 上下文已经是一个工作单元。您只是在包装已经存在的功能并创建一个不需要的间接层。
  • @spender 这是我发现的唯一方法,它可以在保留 DI 并允许我在单元测试中模拟所有内容的同时工作。你有替代方案吗?如果可以的话,我会对改进我的代码感兴趣。
  • 错过了“嘲笑”位。无视我。
猜你喜欢
  • 2014-09-10
  • 1970-01-01
  • 2018-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-28
相关资源
最近更新 更多