4

我在这篇文章中读到,他们使用依赖注入在每个 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 请求上加载存储库实例)。

4

3 回答 3

5

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

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

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

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

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

于 2013-10-12T22:35:35.620 回答
4

当我的团队开始使用依赖注入时,我们正在阅读 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();
    }
}

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

** 当你使用接口时

  1. 在代码中模拟依赖项更容易(一些模拟框架有限制)
  2. 在不更改旧实现的情况下开发和测试新实现更容易。

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

于 2013-10-12T21:48:10.587 回答
2

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

于 2013-10-12T19:08:29.613 回答