在 ASP.NET MVC 3 中使用 Munq IOC 容器版本 3






4.93/5 (14投票s)
Munq IOC 容器版本 3 已在 CodePlex 和 NuGet 包中发布。本文将演示如何将 IOC 容器集成到 ASP.NET MVC3 项目中。
引言
Munq IOC 容器 的 3.0 版本增加了一些新功能,包括文档和 NuGet 打包。Munq 的源代码维护在 CodePlex 上。本文将演示如何使用 NuGet 包将 Munq IOC 容器集成到 ASP.NET MVC 项目中。
在我的示例中,我将重构 AccountController
以使用依赖注入和 Munq IOC 容器。最终,我将实现:
- 将 Munq IOC 容器集成到 ASP.NET 项目中。
- 重构
AccountController
以使用依赖注入。 - 使用所需的注册初始化 IOC 容器。
- 更新单元测试。
最终的解决方案将允许您通过 IOC 容器配置轻松替换 IFormsAuthenticationService
和 IMembershipService
的实现。另外,您可以替换 AccountMembershipService
使用的 MembershipProvider
实例。
背景
以前,我写过关于 Munq IOC 容器的文章:
- Munq IocContainer V2 - 概述
- Munq IOC 容器在 ASP.NET 中的介绍
- 在 ASP.NET MVC 2 Preview 2 中使用 Munq IOC
- Munq IOC 容器 – 创建线程局部存储生命周期管理器
根据收到的反馈和建议,以及需要将 IOC 容器用于 ASP.NET MVC3,我发布了 Munq 的更新版本。除了核心 IOC 容器之外,还提供了 ASP.NET MVC3 IDependencyResolver
和 Common Service Locator
的实现。这三者都可以通过 NuGet 包获取。
Munq IOC 容器最重要的两个新增功能是:
- 自动解析具有最多参数的
public
构造函数。这意味着一个类将通过类类型进行解析,而无需在容器中注册。 - 按类型注册。使用上面的功能,您可以按以下形式注册接口实现:
container.Register<IMyType, MyClass>();
代码展示
首先,创建一个 MVC3 项目,选择 Internet Application 选项。同时选择 ASP.NET 作为视图引擎,并勾选单元测试复选框。这将创建一个简单的起点,包括主页、关于页以及使用 SQL Express 的基于表单的身份验证。
生成并运行应用程序,以便我们知道它能正常工作。同时,运行单元测试以验证它们是否通过。
如果我们查看 AccountController.cs 文件,会发现此控制器的依赖项在 Initialize
方法中进行了配置。
public IFormsAuthenticationService FormsService { get; set; }
public IMembershipService MembershipService { get; set; }
protected override void Initialize(RequestContext requestContext)
{
if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
base.Initialize(requestContext);
}
我们要将其更改为使用依赖注入,因此我们将删除此方法,并添加一个以身份验证和服务为参数的构造函数。此外,FormsService
和 MembershipService
属性暴露了控制器用户不需要的实现细节。我们现在不解决这个问题,因为它会破坏一些单元测试,并且在展示如何实现依赖注入方面并不重要。
快速重构后,我们得到:
public IFormsAuthenticationService FormsService { get; set; }
public IMembershipService MembershipService { get; set; }
public AccountController(IFormsAuthenticationService formsService,
IMembershipService membershipService)
{
FormsService = formsService;
MembershipService = membershipService;
}
生成解决方案后,单元测试会出错,提示 AccountController
没有无参构造函数。
修改 AccountControllerTest.cs 中的 GetAccountController
方法为:
private static AccountController GetAccountController()
{
RequestContext requestContext =
new RequestContext(new MockHttpContext(), new RouteData());
AccountController controller =
new AccountController(new MockFormsAuthenticationService(),
new MockMembershipService())
{
Url = new UrlHelper(requestContext),
};
controller.ControllerContext = new ControllerContext()
{
Controller = controller,
RequestContext = requestContext
};
return controller;
}
此外,Models/AccountModels.cs 中定义的 AccountMembershipService
类有一个无参构造函数。将其删除。同时,将另一个构造函数更改为如下所示:
public class AccountMembershipService : IMembershipService
{
private readonly MembershipProvider _provider;
public AccountMembershipService(MembershipProvider provider)
{
_provider = provider;
}
...
现在我们成功生成了解决方案,并且所有测试仍然通过,但当我们运行它时,点击登录链接时会出现错误。错误如下:
System.MissingMethodException: No parameterless constructor defined for this object.
…堆栈跟踪显示,该错误是由 AccountController
引起的。
现在,我们需要添加 IOC 容器。幸运的是,我创建了一个用于在 MVC3 中使用 Munq IOC 容器的 NuGet 包。我假设您已经在您的 Visual Studio 副本中安装了 NuGet。右键单击 MuncMvc3Sample
项目,然后选择 **添加库包引用...**。这将打开 NuGet 对话框。在在线包中搜索 Munq。您会看到三个选项。安装 Munq.MVC3
包。
这将安装并添加对以下文件的引用:
- Munq.IocContainer.dll (Munq IOC 容器)
- Munq.MVC3.dll (包含实现
System.Web.Mvc.IDependency
接口的MunqDependencyResolver
) - WebActivator.dll (允许
MunqDependencyResolver
自动连接)
此外,还会创建一个名为 App_Start
的目录,其中包含一个文件:MunqMvc3Startup.cs。该文件包含配置 MVC3 以使用 Munq IOC 容器处理其依赖项解析任务的代码。
using System.Web.Mvc;
using Munq.MVC3;
[assembly: WebActivator.PreApplicationStartMethod
(typeof(MunqMvc3Sample.App_Start.MunqMvc3Startup), "PreStart")]
namespace MunqMvc3Sample.App_Start {
public static class MunqMvc3Startup {
public static void PreStart() {
DependencyResolver.SetResolver(new MunqDependencyResolver());
var ioc = MunqDependencyResolver.Container;
// TODO: Register Dependencies
// ioc.Register<IMyRepository, MyRepository>();
}
}
}
确保开发 Web 服务器已停止,以便执行启动代码。现在尝试生成并运行。我们仍然会收到错误。这是因为我们尚未注册 IFormsService
和 IMembershipService
的实现。因此,MVC 会回退到尝试使用无参构造函数创建 AccountController
,但该构造函数不存在。在 MunqMvc3Startup.cs 文件中,注册这些服务。
using System.Web.Mvc;
using Munq.MVC3;
using MunqMvc3Sample.Models;
[assembly: WebActivator.PreApplicationStartMethod(
typeof(MunqMvc3Sample.App_Start.MunqMvc3Startup), "PreStart")]
namespace MunqMvc3Sample.App_Start {
public static class MunqMvc3Startup {
public static void PreStart() {
DependencyResolver.SetResolver(new MunqDependencyResolver());
var ioc = MunqDependencyResolver.Container;
// TODO: Register Dependencies
// ioc.Register<IMyRepository, MyRepository>();
// setup AccountController's dependencies
ioc.Register<IFormsAuthenticationService, FormsAuthenticationService>();
ioc.Register<IMembershipService, AccountMembershipService>();
// AccountMembershipService needs a MembershipProvider
ioc.Register<MembershipProvider>(c => Membership.Provider);
}
}
}
再次停止开发服务器,然后生成并运行。现在,当您单击运行时,将显示登录表单。MVC3 现在正在使用 Munq 来解析依赖项。请注意,我们不必注册 AccountController
类本身。对于类,Munq 会尝试使用具有最多参数的构造函数进行解析。这正是 MVC3 所需要的,也是 Munq 添加此功能的原因。
这意味着,如果您在控制器的构造函数中添加或删除参数(依赖项),只要这些依赖项已注册或为类,它仍然会被解析。
接下来,我想重构 AccountController
类中的 FormsService
和 MembershipService
属性。我使用的是 CodeRush,所以重构非常容易。
private IFormsAuthenticationService _formsService;
private IMembershipService _membershipService;
public AccountController(IFormsAuthenticationService formsService,
IMembershipService membershipService)
{
_formsService = formsService;
_membershipService = membershipService;
}
生成后,使用该属性的单元测试会遇到许多错误。我不会在此处详细介绍更改,但您可以在随附的源文件中看到它们。
结论
这个示例的结果是一个 Visual Studio 项目,可用作未来使用 ASP.NET MVC3 和 Munq IOC 容器进行开发的模板。
历史
- 首次发布