使用 Unity IoC 容器在 MVC 中实现依赖注入






4.70/5 (21投票s)
在这篇文章中,我们将学习如何使用 Unity 容器实现依赖注入。
使用 Unity IoC 容器在 MVC 中实现依赖注入
如果您有软件设计经验,并且遵循(或至少尝试遵循)完美的設計模式和原则,那么依赖注入、解耦架构和控制反转 (IoC) 对您来说是非常常见的术语。您可能在各种编程语言中(使用或不使用任何 IoC 容器)拥有依赖注入实现的实践经验。在本文中,我们将讨论依赖注入和 IoC 容器之间的关系,然后我们将了解 IoC 容器和依赖注入如何并排工作。
什么是 IoC 容器?
DI 容器或 IoC 容器是一个软件框架,用于创建依赖项并在需要时自动注入它们。说实话,有些依赖项容器在需要解决依赖项时就像魔法一样工作。市场上有许多这样的框架可以简化我们的工作,这里有一些在 .NET 环境中工作的框架。因此,选择完全取决于您,它们各自都有自己的基准和性能,因此请根据您的项目和要求明智地选择。由于本文并非专门针对 IoC 容器,因此我不会过多讨论它。在本文中,我们将使用 Unity 作为 IoC 容器来解决依赖关系。
让我们实现带有依赖项的控制器
正如标题所示,我们将实现 MVC 架构以帮助理解这个概念,然后我们将创建两个控制器,每个控制器都有一些依赖项,并了解如何使用 IoC 容器来解决这些依赖项。以下是第一个控制器的代码。实现非常简单,我们创建了一个 `Ilogger` 接口,并且 `ILogger` 有两个实现:一个是 `ActualLogger`,它尚未完成,作为替代,我们实现了另一个类 `FakeLogger`,我们将在代码开发中使用它。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCIoC.Controllers
{
public interface ILogger
{
Boolean Log();
}
public class ActualLogger : ILogger
{
public Boolean Log()
{
throw new NotImplementedException();
}
}
public class FakeLogger : ILogger
{
public Boolean Log()
{
return true;
}
}
public class HomeController : Controller
{
public readonly ILogger logger = null;
public HomeController(ILogger tmpLogger)
{
logger = tmpLogger;
}
public ActionResult Index()
{
//perform logging information
logger.Log();
return View();
}
}
}
所以,我们的想法是,如果我们的实际实现处于开发阶段,我们仍然可以使用某种替代方法继续我们的控制器开发,并且及时可以更改它而不会影响现有代码。因此,我们看到 Home 控制器有一个参数化构造函数。作为参数,它将采用依赖对象的实际实现。让我们创建一个另一个控制器;实现将与上面的完全相同。我只是想展示如何在多个控制器中解决依赖关系。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCIoC.Controllers
{
public interface IService
{
Boolean Call();
}
public class RealService : IService
{
//Real service is not developed yet.
public bool Call()
{
throw new NotImplementedException();
}
}
public class FakeService : IService
{
public bool Call()
{
return true;
}
}
public class ValueController : Controller
{
public readonly IService service = null;
public ValueController(IService tmpService)
{
service = tmpService;
}
public ActionResult Index()
{
//User service to implement business logic
service.Call();
return View();
}
}
}
好了,我们已经设置好了一切。现在我们将引用 Unity 框架。如果您使用的是 Visual Studio,则可以使用 NuGet 包管理器来引用。我以下面的引用为例
现在,我们将从 `DefaultControllerFactory` 类实现我们自己的控制器工厂类。您还可以实现其他选项。例如,`IController` 执行相同的操作。在这里,我们定义了 `ControllerFactory` 并从 `DefaultControllerFactory` 类派生。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity;
using MVCIoC.Controllers;
namespace MVCIoC.Models
{
public class ControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
throw new ArgumentNullException("controllerType");
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(string.Format(
"Type requested is not a controller: {0}",
controllerType.Name),
"controllerType");
return MvcUnityContainer.Container.Resolve(controllerType) as IController;
}
catch
{
return null;
}
}
}
public static class MvcUnityContainer
{
public static UnityContainer Container { get; set; }
}
}
您可以看到我们正在 try 块中解决依赖关系,它将通过解决依赖关系来创建一个控制器对象。对于 Unity 容器,我们将创建一个 `Bootstrapper` 类来在一个文件中设置所有依赖项。请查看下面的代码。虽然实现 Bootstrapper 不是强制性的,但实现它始终是一个好习惯。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Mvc;
using MVCIoC.Controllers;
namespace MVCIoC.Models
{
public class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IService, FakeService>();
container.RegisterType<ILogger, FakeLogger>();
MvcUnityContainer.Container = container;
return container;
}
}
}
请注意,我们已将 `FakeService` 和 `FakeLogger` 与其接口映射在一起,因为我们的目标是使用 `FakeService` 和 `FakeLogger` 的实现。一旦完成原始实现的开发,您只需在此处更改,无需触摸您的控制器代码。现在最终实现是注册。我们必须在 MVC 通道中注册我们的 IoC 容器。只需修改您的 `Application_Start()` 代码,如下所示。
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
//Initialize IoC container/Unity
Bootstrapper.Initialise();
//Register our custom controller factory
ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
}
现在,是时候运行应用程序了。一旦我们调用 Home 控制器,您将看到 `FakeLogger` 的对象已注入到 Home 控制器的构造函数中。
总结
市场上有很多 IoC 容器。您可以选择其中任何一个,所有 IoC 容器的工作方式都大致相同。