使用 DI 在每个 MVC 请求上加载存储库实例

本文关键字:加载 存储 实例 请求 MVC DI 使用 | 更新日期: 2023-09-27 18:35:10

我在这篇文章中读到他们正在使用依赖注入来加载每个 mvc 请求上的存储库实例。

不确定我是否正确理解,但我目前正在我的 mvc 应用程序中使用。 UserRepository实现IUserRepository接口。此接口注入到控制器构造函数中

public class UserController : Controller
{
   private IUserRepository repository;
   public UserController(IUserRepository rep)
   { repository = rep; }
   public UserController() : this(new UserRepository()) {}
}

但我没有看到使用此接口(IUserRepository)的任何好处,我可以在没有接口的情况下使用UserRepository。显然,有人认为更聪明的人是正确的方法(我在 apress mvc4 书中找到了它),我恳请某人详细说明为什么这是更好的方法,而不是使用没有接口的存储库。

考虑到这一点,我会要求任何人分享有关如何实现此方法的具体示例或链接(使用依赖注入在每个 mvc 请求上加载存储库实例)。

使用 DI 在每个 MVC 请求上加载存储库实例

DI 背后的主要思想是迫使你看到大局而不是具体的实现。

你的

控制器需要获取用户,但它不应该关心具体的实现(你的仓库是从数据库、Web 服务、xml 文件等中获取用户,还是使用 Linq2Sql、EntityFramework、Dapper 或其他底层的东西)。

你的控制器依赖于可以在构造函数、属性或方法中注入的代码段,但它并不真正关心具体的实现。

DI 消除了控制器和存储库之间的紧密耦合,允许您通过模拟存储库来编写单元测试,并且您可以轻松地更改存储库的具体实现(例如,使用 PetaPoco 而不是 EntityFramework),而无需触及其余代码。

您还应该查看 SOLID 原则:http://en.wikipedia.org/wiki/SOLID_(对象oriented_design)

当我的团队开始使用依赖注入时,我们正在阅读Steven Sanderson的一本好书"Pro ASP.NET MVC 2 Framework"。在这本书中,他描述了如何使用Castle Windsor,一个流行的依赖注入框架。在另一本书"Pro ASP.NET MVC 3 Framework"中,据我所知,描述了如何使用Ninject(另一个框架)。

为了使用温莎城堡:

首先,您必须编写控制器工厂的自定义实现:

/// <summary>
/// Controller factory the class is to be used to eliminate hard-coded dependencies 
/// between controllers and other components
/// </summary>
public class ControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;
    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }
    public override void ReleaseController(IController controller)
    {
        container.Release(controller.GetType());
    }
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        return (IController)container.Resolve(controllerType);
    }
}

然后,您必须为所有控制器编写安装程序。

/// <summary>
/// Castle windsor installer for controller components.
/// </summary>
public class ControllersInstaller : IWindsorInstaller
{
    /// <summary>
    /// Performs the installation in the <see cref="T:Castle.Windsor.IWindsorContainer"/>.
    /// </summary>
    /// <param name="container">The container.</param>
    /// <param name="store">The configuration store.</param>
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Classes.FromThisAssembly()
                .BasedOn<IController>()
                .LifestyleTransient()
        );
    }
}

如果您希望将存储库解析为依赖项,则还应为它们编写安装程序。它将类似于ControllersInstaller,但生活方式将是LifestylePerWebRequest()。PerRequestLifestyle应该在web.config文件中注册。

<httpModules>
  <add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
</httpModules>

然后,当应用程序在 Global.asax 中启动时,您必须创建一个容器实例.cs:

public class MvcApplication : System.Web.HttpApplication
{
    private static IWindsorContainer container;
    protected void Application_Start()
    {
        container = new WindsorContainer();
        container.Install(FromAssembly.This());
        //Set the controller builder to use our custom controller factory
        var controllerFactory = new WindsorControllerFactory(container);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
    }
    protected void Application_End()
    {
        container.Dispose();
    }
}

还有一个指向温莎城堡文档的链接,您可以在其中找到有关使用生活方式和 ASP.NET MVC 3 应用程序教程的更多信息。

** 使用接口时

  1. 在代码中模拟依赖项更容易(一些模拟框架有限制)
  2. 开发新实现并测试它更容易,而无需更改旧实现。

** 如果已实现和设置控制器工厂,则不需要控制器中的默认构造函数。

接口的主要优点是它们鼓励抽象。如果你想模拟一个完全不同的实现(例如,在执行单元测试时,无论如何都应该:)这样做,你只需将IUserRepository的另一个实现注入到你的UserController构造函数。在我看来,这是使用接口的主要优势之一。