【问题标题】:Service Locator Alternative in ASP.NET MVC [closed]ASP.NET MVC 中的服务定位器替代方案 [关闭]
【发布时间】:2012-12-18 06:26:16
【问题描述】:

阅读 Mark Seemann's blog post 和引用它的 this response 后,我了解使用 Service Locator 模式优于通过类构造函数进行依赖注入的缺点。我还阅读了这个Dependency Injection with Ninject, MVC 3 and using the Service Locator Pattern,它也讨论了这个问题。

但是,我的问题涉及这个特殊情况:

public class MyController
{
    public void GetData()
    {
        using (var repository = new Repository())
        {
            // Use the repository which disposes of an Entity Framework
            // data context at the end of its life.
        }
    }

    // Lots of other methods.
}

这里我有一个控制器,其中包含一个调用存储库的方法,该存储库自动实例化内部实体框架数据上下文。使用这个单一数据上下文,因为存储库中的每个方法都会调用该上下文,因此在存储库对象的整个生命周期内共享单个上下文似乎是有意义的。

现在,由于控制器类很大,因此这个给定的存储库不会被使用的可能性更大。正如我假设(可能是错误的)这种实例化 DC 是一项昂贵的操作,我宁愿避免这样做。使用服务定位器模式可以让我推迟实例化,直到实际需要上下文,但鉴于上述链接中反对它的有效参数,我宁愿避免它。

所以我想知道的是,在上述情况下,是否有一种更有效的使用依赖注入的方法可以防止我不必要地实例化我的存储库和底层数据上下文。

【问题讨论】:

  • 这个问题太主观了。 “更好”是非常模糊的。
  • 我已经编辑了这个问题,试图澄清我在问什么。

标签: asp.net-mvc design-patterns dependency-injection service-locator


【解决方案1】:

我认为答案取决于您的存储库如何管理连接。如果它在构建时打开了与数据库的连接,那么我认为问题出在您的存储库上,而不是依赖注入。您的存储库应仅在发出请求时打开连接,并在收到响应后立即关闭它。按照这种模式,依赖注入仍然有意义。


根据您的更新,您最好还是使用 DI,因为 EF 在构造时不会打开与数据库的连接,只有在发出请求时才会打开。您的数据上下文足够小,值得为每个请求创建上下文所需的少量开销。


还有一条评论:您还应该考虑将数据上下文注入到您的存储库中,并让您的 DI 容器控制上下文的生命周期。这允许您在单个请求期间在一个或多个存储库中使用相同的上下文。 Here's a pretty good resource explaining how to implement the Repository and Unit of Work patterns with Entity Framework in ASP.NET MVC.

【讨论】:

  • 我在编写存储库时考虑过这一点,但是由于存储库中的每个方法都使用相同的连接,因此将连接的生命周期与存储库实例的生命周期联系起来很方便。有充分的理由不这样做吗?
  • 如果您的控制器在 ASP.NET MVC 中使用,那么每个方法都不会使用相同的连接,因为每个请求都会实例化一个新的控制器,因此会实例化一个新的存储库和一个新的连接。
  • 我更新了问题,提供了更多信息以回应您的评论。
  • 感谢您的更新。关于上下文创建的良好推理。
  • 用关于将 EF 与存储库和工作单元模式结合使用的良好资源更新了我的答案。
【解决方案2】:

由于控制器类很大,连接不会用于任何给定构造的可能性更大,因此实例化存储库并使用标准的基于构造函数的 DI 打开连接是没有意义的.

注入 LazyFunc 或工厂代替:

public class MyController
{
    // Use constructor injection to populate this.
    private Func<MyRepository> _repository;

    public void GetData()
    {
        using (var repository = _repository())
        {
            // ...
        }
    }
}

这样您就可以避免在需要它们之前创建实际实例。

@sellmeadog 的回答也不错。

【讨论】:

  • 如果您无法控制存储库,我会推荐这种方法。
【解决方案3】:

您在问是否应该将数据库连接注入到 Repository 构造函数中?您可以尝试使用 Abstract Factory 设计模式注入数据库连接 factory 而不是实际的数据库连接。

public class MyController
{
    public void GetData()
    {
        using (var repository = new Repository(IDatabaseConnectionFactory dbConnFac))
        {
            // Use the repository which disposes of a database connection
            // at the end of its life.
        }
    }

    // Lots of other methods.
}

通过这种方式,您可以获得依赖注入的好处,同时仍然允许存储库管理其数据库连接的生命周期。

【讨论】:

    猜你喜欢
    • 2010-10-18
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 2020-12-27
    相关资源
    最近更新 更多