65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (14投票s)

2011 年 4 月 2 日

CPOL

5分钟阅读

viewsIcon

59299

downloadIcon

693

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 容器配置轻松替换 IFormsAuthenticationServiceIMembershipService 的实现。另外,您可以替换 AccountMembershipService 使用的 MembershipProvider 实例。

背景

以前,我写过关于 Munq IOC 容器的文章:

根据收到的反馈和建议,以及需要将 IOC 容器用于 ASP.NET MVC3,我发布了 Munq 的更新版本。除了核心 IOC 容器之外,还提供了 ASP.NET MVC3 IDependencyResolverCommon 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);
}

我们要将其更改为使用依赖注入,因此我们将删除此方法,并添加一个以身份验证和服务为参数的构造函数。此外,FormsServiceMembershipService 属性暴露了控制器用户不需要的实现细节。我们现在不解决这个问题,因为它会破坏一些单元测试,并且在展示如何实现依赖注入方面并不重要。

快速重构后,我们得到:

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 IOC on NuGet - Click to enlarge image

这将安装并添加对以下文件的引用:

  • 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 服务器已停止,以便执行启动代码。现在尝试生成并运行。我们仍然会收到错误。这是因为我们尚未注册 IFormsServiceIMembershipService 的实现。因此,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 类中的 FormsServiceMembershipService 属性。我使用的是 CodeRush,所以重构非常容易。

private IFormsAuthenticationService _formsService;
private IMembershipService          _membershipService;

public AccountController(IFormsAuthenticationService formsService,
                                    IMembershipService membershipService)
{
    _formsService      = formsService;
    _membershipService = membershipService;
}    

生成后,使用该属性的单元测试会遇到许多错误。我不会在此处详细介绍更改,但您可以在随附的源文件中看到它们。

结论

这个示例的结果是一个 Visual Studio 项目,可用作未来使用 ASP.NET MVC3 和 Munq IOC 容器进行开发的模板。

历史

  • 首次发布
© . All rights reserved.