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

使用 Munq IOC 和 ASP.NET MVC 2 Preview 2

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2009 年 10 月 30 日

CPOL

4分钟阅读

viewsIcon

33374

在本文中,我将介绍如何修改默认的 ASP.NET MVC 2 应用程序以使用 Munq IOC 容器。

概述

在本文中,我将介绍如何修改默认的 ASP.NET MVC 2 应用程序以使用 Munq IOC 容器。这是一个相当简单的过程,在这个过程中,我们将为框架创建一个自定义的 Controller Factory,您可以在其他应用程序中使用它。

上一篇文章可以在我的博客上找到:Introduction to Munq IOC Container for ASP.NET,或者在 CodeProject 上找到:Introduction to Munq IOC Container for ASP.NET。本文开发了基础应用程序,我们将在后续文章中在此基础上研究 Munq IOC 的功能。

步骤 1:创建 MVC 2 项目

打开 Visual Studio 并创建一个新的 MVC 2 应用程序。为它起任何名字。我将其命名为 FinalApp,以区别于我创建的作为参考的 InitialApp

构建应用程序,熟悉 AccountController 的登录/注册/登出功能。提示:登录可在页面右上角找到。

步骤 2:移除 AccountController 中的依赖项

AccountControllerFormsAuthenticationServiceAccountMembershipService 这两个具体实现存在硬编码依赖,如下面粗体显示的行所示。

    // This constructor is used by the MVC framework to instantiate the controller using
    // the default forms authentication and membership providers.

    public AccountController()
        : this(null, null)
    {
    }

    // This constructor is not used by the MVC framework but is instead provided for ease
    // of unit testing this type. See the comments at the end of this file for more
    // information.
    public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
    {
        FormsAuth = formsAuth ?? new FormsAuthenticationService();
        MembershipService = service ?? new AccountMembershipService();
    }

要“修复”此问题,您需要:

  1. 添加对 Munq.DI.dll 的引用。
  2. global.asax
    1. 创建一个应用程序级别的 Container 变量
    2. Application_Start 中向容器注册依赖项
  3. 更改 AccountController 的默认构造函数以解析依赖项
  4. 更改带参数的构造函数以检查 null 参数

Controllers 的注册和解析将在稍后处理。

完成步骤 1 和 2 后,global.asax 应如下所示。更改已高亮显示。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Munq.DI;
using FinalApp.Controllers;

namespace FinalApp
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static Container IOC {get; private set;}
        
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                 new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            IOC = new Container();
            RegisterInterfaces();
            RegisterRoutes(RouteTable.Routes);
        }

        private void RegisterInterfaces()
        {
            IOC.Register<IFormsAuthentication>( ioc => new AccountMembershipService()); 
            IOC.Register<IMembershipService>( ioc => new FormsAuthenticationService());
     }
}

完成步骤 3 和 4 后,AccountController 的构造函数应如下所示:

    [HandleError]
    public class AccountController : Controller
    {

        // This constructor is used by the MVC framework to instantiate the controller using
        // the default forms authentication and membership providers.
        public AccountController()
            : this(    MvcApplication.IOC.Resolve<IFormsAuthentication>(), 
              MvcApplication.IOC.Resolve<IMembershipService>())
        {
        }

        // This constructor is not used by the MVC framework but is instead provided for ease
        // of unit testing this type. See the comments at the end of this file for more
        // information.
        public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
        {
            // Validate the parameters
            if (formsAuth == null)
                throw new ArgumentNullException("formsAuth");
    
            if (service == null)
                throw new ArgumentNullException("service");
            
            // set the dependencies    
            FormsAuth = formsAuth;
            MembershipService = service;
        }
        ...

现在构建并运行应用程序。它的运行应该与我们开始之前一样。

是的,看起来我们做了很多工作才获得了相同的功能,并将两个依赖项替换为对 IOC 容器的依赖。我们将在下一步中移除这个依赖项。

步骤 3:创建 IOC 感知的 ControllerFactory

为了移除控制器对 IOC 容器的依赖,有必要创建一个自定义的 ControllerFactory。这个 ControllerFactory 将使用 IOC 容器来创建正确的控制器并解析任何构造函数依赖项。

由于我们希望在未来的项目中重用它,我们将

  1. 创建一个新的类库项目
  2. 添加对 Munq.DISystem.Web.MVCSystem.Web.Routing 的引用
  3. 创建 MunqControllerFactory
  4. 注册新的 Controller Factory 并注册 controllers
  5. AccountController 中移除对 Container 的依赖
  6. 修复测试

完成步骤 1-3 后,项目应如下所示:

clip_image001[4]

因为 Munq 可以按名称注册工厂,并且 Munq 处理由 DefaultControllerFactory 类执行的工厂缓存和查找,所以我们可以派生一个名为 MunqControllerFactory 的新类,它实现 IControllerFactory 接口CreateController 方法的参数之一是控制器的名称,不带 Controller 后缀。这意味着我们可以按名称注册控制器。需要编写的另一个方法是 ReleaseController 方法,它在需要时处理控制器的处置。如下所示。请注意,构造函数接受 Munq Container 作为参数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;

using Munq.DI;

namespace Munq.MVC
{
    public class MunqControllerFactory : IControllerFactory
    {
        public Container IOC { get; private set; }

        public MunqControllerFactory(Container container)
        {
            IOC = container;
        }

        #region IControllerFactory Members

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            try
            {
                return IOC.Resolve<IController>(controllerName);
            }
            catch
            {
                return null;
            }
        }

        public void ReleaseController(IController controller)
        {
            var disposable = controller as IDisposable;

            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

        #endregion
    }
}

下一步是将 MunqControllerFactory 注册为默认控制器工厂。打开 global.asax 并按如下方式修改:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Munq.DI;
using Munq.MVC;
using FinalApp.Controllers;

namespace FinalApp
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static Container IOC { get; private set; }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            InitializeIOC();
            RegisterRoutes(RouteTable.Routes);
        }

        private void InitializeIOC()
        {
            // Create the IOC container
            IOC = new Container();

            // Create the Default Factory
            var controllerFactory = new MunqControllerFactory(IOC);

            // set the controller factory
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);

            // Register the dependencies
            IOC.Register<>IFormsAuthentication>(ioc => new FormsAuthenticationService());
            IOC.Register<IMembershipService>(ioc => new AccountMembershipService());

            // Register the Controllers
            IOC.Register<IController>("Home", ioc => new HomeController());
            IOC.Register<IController>("Account",
                    ioc => new AccountController(ioc.Resolve<IFormsAuthentication>(),
                                                  ioc.Resolve<IMembershipService>())
            );
        }
    }
}

现在我们准备从 AccountController 中移除对 IOC 的依赖。这很简单,只需移除默认构造函数,因为它引用了 IOC 容器。MunqControllerFactory 和 Munq IOC 将处理其余构造函数的依赖项解析工作。AccountController 的开头应如下所示:

    ...
    [HandleError]
    public class AccountController : Controller
    {
        public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
        {
            // Validate the parameters
            if (formsAuth == null)
                throw new ArgumentNullException("formsAuth");

            if (service == null)
                throw new ArgumentNullException("service");

            // set the dependencies    
            FormsAuth = formsAuth;
            MembershipService = service;
        }
    ...

唯一剩下的是注释掉 AccountController 的单元测试,该测试正在测试我们刚刚移除的构造函数。

...
        //[TestMethod]
        //public void ConstructorSetsPropertiesToDefaultValues()
        //{
        //    // Act
        //    AccountController controller = new AccountController();

        //    // Assert
        //    Assert.IsNotNull(controller.FormsAuth, "FormsAuth property is null.");
        //    Assert.IsNotNull(controller.MembershipService, "MembershipService property is null.");
        //}
...

现在您可以构建、运行测试和应用程序了。我们现在拥有了一个平台,可以在其中演示不同的生命周期管理器以及它们如何简化应用程序的状态管理。但这将是下一篇文章的内容。在接下来的几篇文章中,我将构建一个真实世界的应用程序,我还没有决定具体内容,请给我一些您想看到内容的建议。

注意:此版本的 MunqControllerFactory 不支持 MVC 2 的 Areas 功能。这将在未来的文章中得到纠正。

del.icio.us 标签: ,,,

© . All rights reserved.