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

如何在 ASP.NET MVC 框架中使用 Unity 容器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (12投票s)

2010年8月5日

CPOL

2分钟阅读

viewsIcon

80767

本文解释了如何在 ASP.NET MVC 框架中使用 Unity IoC 容器。

引言

过去,我写过一篇关于 如何在 ASP.NET 中使用 Unity 容器 的文章。
在本文中,我将展示并解释如何在 ASP.NET MVC 框架 中使用 Unity IoC 容器,以便使我们应用程序中的各个方面更加解耦。

构建容器

就像在之前的文章中一样,首先要做的是构建容器本身。我将使用与之前的文章中相同的方法,以便在应用程序执行期间持久化 Unity 容器的状态。放置 Unity 容器的正确位置是作为 Global.asax 文件的一部分,作为当前运行的 HTTP 应用程序的属性。我将使用过去使用过的相同接口,如下所示:

public interface IContainerAccessor
{
    IUnityContainer Container { get; }
}

构建接口后,在 Global.asax 文件中的 Global 类中实现它。

public class MvcApplication : HttpApplication, IContainerAccessor
{
    #region Members

    private static IUnityContainer _container;

    #endregion

    #region Properties

    /// <summary>
    /// The Unity container for the current application
    /// </summary>
    public static IUnityContainer Container
    {
        get
        {
            return _container;
        }
    }

    #endregion

    #region IContainerAccessor Members

    /// <summary>
    /// Returns the Unity container of the application 
    /// </summary>
    IUnityContainer IContainerAccessor.Container
    {
        get { return Container; }
    }

    #endregion

    #region Application Events

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
        InitContainer();
        ControllerBuilder.Current.SetControllerFactory(typeof(UnityControllerFactory));
    }

    protected void Application_End(object sender, EventArgs e)
    {
        CleanUp();
    }

    #endregion

    #region Methods

    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
        );
    }

    private static void InitContainer()
    {
        if (_container == null)
        {
            _container = new UnityContainer();
        }

        // Register the relevant types for the 
        // container here through classes or configuration
        _container.RegisterType<IMessageService, MessageService>();
    }

    private static void CleanUp()
    {
        if (Container != null)
        {
            Container.Dispose();
        }
    }

    #endregion
}

实现很简单。你为容器创建一个 getter,它是 HTTP 应用程序的成员。同样,在应用程序启动事件中,我在容器中注册所有相关的依赖项,并在应用程序结束时处理容器。

Unity 控制器工厂

Global.asax 的这个新实现中真正重要的变化是控制器工厂的设置,你需要提供它。控制器工厂的职责是为传入的 HTTP 请求实例化相关的控制器。你应该实现 IControllerFactory 接口,以便能够插入你的工厂实现。
UnityControllerFactory 的代码如下:

public class UnityControllerFactory : IControllerFactory
{
    #region IControllerFactory Members

    public IController CreateController
	(RequestContext requestContext, string controllerName)
    {
        IContainerAccessor containerAccessor =
            requestContext.HttpContext.ApplicationInstance as IContainerAccessor;

        Assembly currentAssembly = Assembly.GetExecutingAssembly();
        var controllerTypes = from t in currentAssembly.GetTypes()
                              where t.Name.Contains(controllerName + "Controller")
                              select t;

        if (controllerTypes.Count() > 0)
        {
            return containerAccessor.Container.Resolve
			(controllerTypes.First()) as IController;
        }
        return null;    
    }

    public void ReleaseController(IController controller)
    {
        controller = null;
    }

    #endregion
}

主要要做的是实现 IControllerFactory 接口的 CreateController 方法。我使用请求上下文参数来检索当前应用程序实例,并从中,使用 IContainerAccessor 接口获取 Unity 容器。我还需实例化相关的控制器类,这由 Unity 容器为我完成。

容器 将通过 Resolve 方法将依赖项注入到控制器中,我们将获得我们想要的 依赖注入 功能。

要注入的类

我还编写了一个 MessageService,这是一个返回消息并继承自
声明 GetMessage 方法的 IMessageService

public interface IMessageService
{
    string GetMessage();
}

public class MessageService : IMessageService
{
    #region IMessageService Members

    public string GetMessage()
    {
        return "Hello Controller!";
    }

    #endregion
} 

控制器

这个难题的最后一部分是控制器类。我使用以下代码实现了 HomeCotroller 类:

[HandleError]
public class HomeController : Controller
{
    #region Members

    [Dependency]
    public IMessageService MessageService { get; set; }        

    #endregion

    #region Actions

    public ActionResult Index()
    {
        ViewData["Message"] = MessageService.GetMessage();
        return View();
    }

    public ActionResult About()
    {
        return View();
    }

    #endregion
}

UnityControllerFactory 会将 MessageService 属性的依赖项注入到相关的类中,就这么简单。为了运行这个,你必须创建一个新的 MVC 框架应用程序,添加我编写的类,并将提供的 HomeController 更改为我编写的实现。

摘要

让我们总结一下。我展示了一个如何在 ASP.NET MVC 框架 应用程序中使用 Unity 容器 的示例。这是一个非常简单的例子,可以帮助你开始在你的 MVC Web 应用程序中使用 Unity

历史

  • 2010年8月5日:初始发布
© . All rights reserved.