ASP.NET MVC 的依赖注入,我的整理

来源:岁月联盟 编辑:exp 时间:2011-10-26

 

最近留意了一下ASP.NET MVC 的依赖注入,也看了不少相关的文章,自己也尝试了两种,分别为NInject 和Unity ,

 

在使用的过程中,也渐渐的了解了依赖注入的思想,于是从网上下载了一些相关的代码,直接拿来用之,包括来自微软官方的,

 

也有来自国外牛人博客的,但是使用当中也发生了一些问题,主要问题就是,当客户端请求一个不存在的Controller或者Action的时候

 

(甚至是请求一个不存在的图片或者资源),会产生异常,网上的大部分代码都会产生错误,这跟使用什么样的DI框架没有关系,

 

原因就出在覆盖DefaultControllerFactory 的GetControllerInstance 方法的实现上,当遇到不存的Controller 或者Action 的时候,

 

抛出的是自定义的异常,而不是HTTP 异常,于是打开了MVC 的源码,仔细阅读了DefaultControllerFactory.GetControllerInstance 的实现,

 

发现如下代码片断:

 

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) {

    if (controllerType == null) {

        throw new HttpException(404,

            String.Format(

                CultureInfo.CurrentUICulture,

                MvcResources.DefaultControllerFactory_NoControllerFound,

                requestContext.HttpContext.Request.Path));

    }

    if (!typeof(IController).IsAssignableFrom(controllerType)) {

        throw new ArgumentException(

            String.Format(

                CultureInfo.CurrentUICulture,

                MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase,

                controllerType),

            "controllerType");

    }

    try {

        return (IController)Activator.CreateInstance(controllerType);

    }

    catch (Exception ex) {

        throw new InvalidOperationException(

            String.Format(

                CultureInfo.CurrentUICulture,

                MvcResources.DefaultControllerFactory_ErrorCreatingController,

                controllerType),

            ex);

    }

}

 //注意,它抛出的是Http 404 的异常,就这么点差别,因此经过改良,我也同样的解决了这个问题,下面就是我定义的ControllerFactory:

 

 //UnityControllerFactory.cs: 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

using System.Reflection;

using Microsoft.Practices.Unity;

using System.Globalization;

 

/// <summary>

/// 依赖注入ControllerFactory

/// </summary>

/// <remarks>

/// 2010-09-18 [Max] 创建。

/// </remarks>

public class UnityControllerFactory : DefaultControllerFactory

{

    /// <summary>

    /// 创建一个Controller 类实例,覆盖基类方法

    /// </summary>

    /// <param name="aRequestContext">Http请求上下文对象</param>

    /// <param name="aControllerType">Controller类型</param>

    /// <returns>

    /// 返回IController 类实例。

    /// </returns>

    /// <remarks>

    /// 2010-10-09 [Max] 创建。

    /// </remarks>

    protected override IController GetControllerInstance(RequestContext aRequestContext, Type aControllerType)

    {

        //不适用的方式:

        //if ( aControllerType == null )

        //{

        //    throw new ArgumentNullException( "aControllerType" );

        //}

 

        //if ( !typeof( IController ).IsAssignableFrom( aControllerType ) )

        //{

        //    throw new ArgumentException( string.Format( "{0} 不是Controller。", aControllerType.Name ), "aControllerType" );

        //}

        //适用的方式:

        if ( aControllerType == null )

        {

            throw new HttpException( 404, String.Format( CultureInfo.CurrentUICulture, "未发现指定的Controller {0}。", aRequestContext.HttpContext.Request.Path ) );

        }

        if ( !typeof( IController ).IsAssignableFrom( aControllerType ) )

        {

            throw new ArgumentException( String.Format( CultureInfo.CurrentUICulture, "{0} 不是Controller。", aControllerType ), "aControllerType" );

        }

        try

        {

            IUnityContainer container = GetContainer( aRequestContext );

            return (IController) container.Resolve( aControllerType );

        }

        catch ( Exception ex )

        {

            throw new InvalidOperationException( String.Format( CultureInfo.CurrentUICulture, "无法创建Controller {0}。", aControllerType ), ex );

        }

    }

 

    /// <summary>

    /// 获取依赖注入容器对象

    /// </summary>

    /// <param name="aContext">Http请求上下文对象</param>

    /// <returns>

    /// 返回IUnityContainer 类实例。

    /// </returns>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual IUnityContainer GetContainer( RequestContext aContext )

    {

        if ( aContext == null )

        {

            throw new ArgumentNullException( "aContext" );

        }

 

        var unityApp = aContext.HttpContext.ApplicationInstance as IUnityMvcApplication;

        if ( unityApp == null )

        {

            throw new InvalidOperationException( "MvcHttpApplication 对象必须从UnityMvcApplication 继承。" );

        }

 

        IUnityContainer container = unityApp.Container;

        if ( container == null )

        {

            throw new InvalidOperationException( "依赖注入容器对象无法访问,请查看您的MvcHttpApplication 类定义是否正确。" );

        }

        return container;

    }

}

 

 

 

 

 

 //IUnityMvcApplication.cs:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Practices.Unity;

 

/// <summary>

/// 依赖注入容器访问接口

/// </summary>

/// <remarks>

/// 2010-09-18 [Max] 创建。

/// </remarks>

public interface IUnityMvcApplication

{

    /// <summary>

    /// 依赖注入容器属性

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    IUnityContainer Container { get; }

}

 

 

 

 

 

 

// 下面这两个单元的代码,由于公司的特殊应用,封装的比较死,不太好,不建议照搬,仅供参考。

 

//UnityMvcApplication.cs:

 

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

using System.Reflection;

using Microsoft.Practices.Unity;

 

/// <summary>

/// Mvc 应用程序类。

/// </summary>

/// <remarks>

/// 2010-09-18 [Max] 创建。

/// </remarks>

public class UnityMvcApplication : HttpApplication, IUnityMvcApplication

{

 

    private static IUnityContainer _UnityContainer;

 

    /// <summary>

    /// 静态依赖注入容器属性

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected static IUnityContainer Container

    {

        get

        {

            if (_UnityContainer == null)

            {

                _UnityContainer = new UnityContainer();

            }

            return _UnityContainer;

        }

    }

 

    /// <summary>

    /// 实现IMvcApplication接口的依赖注入容器属性

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    IUnityContainer IUnityMvcApplication.Container

    {

        get

        {

            return Container;

        }

    }

 

    #region override methods

    /// <summary>

    /// 应用程序启动事件

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void Application_Start()

    {

        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);

        RegisterRoutes(RouteTable.Routes);

        RegisterDependency();

        RegisterControllerFactory();

    }

 

    /// <summary>

    /// 应用程序结束事件

    /// </summary>

    /// <param name="sender">事件发起者</param>

    /// <param name="e">事件参数</param>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void Application_End( object sender, EventArgs e )

    {

        CleanUp();

    }

    #endregion

 

    #region protected virtual methods

    /// <summary>

    /// 注册全局过滤器

    /// </summary>

    /// <param name="aFilters">全局过滤器集合</param>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void RegisterGlobalFilters(GlobalFilterCollection aFilters)

    {

        aFilters.Add(new HandleErrorAttribute());

    }

 

    /// <summary>

    /// 注册URL路由

    /// </summary>

    /// <param name="aRoutes">路由器对象</param>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void RegisterRoutes(RouteCollection aRoutes)

    {

        aRoutes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        aRoutes.MapRoute(

            "Default", // Route name

            "{controller}/{action}/{aId}", // URL with parameters

            new { controller = "Home", action = "Index", aId = UrlParameter.Optional } // Parameter defaults

        );

    }

 

    /// <summary>

    /// 注册依赖注入对象

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void RegisterDependency()

    {

 

    }

 

    /// <summary>

    /// 注册Controller工厂

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void RegisterControllerFactory()

    {

        ControllerBuilder.Current.SetControllerFactory(typeof(UnityControllerFactory));

    }

 

    /// <summary>

    /// 清除资源

    /// </summary>

    /// <remarks>

    /// 2010-09-18 [Max] 创建。

    /// </remarks>

    protected virtual void CleanUp()

    {

        if (_UnityContainer != null)

        {

            _UnityContainer.Dispose();

        }

    }

    #endregion

 

}

 

 

 

 

 

//Global.asax.cs:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

using System.Reflection;

using Microsoft.Practices.Unity;

 

public class MvcApplication : UnityMvcApplication

{

    protected override void Application_Start( )

    {

        base.Application_Start( );

    }

 

    protected override void RegisterDependency( )

    {

        Container.RegisterType<IRDict, DictRepository>( );

        Container.RegisterType<IRStudent, StudentRepository>( );

    }

}

 

 

 

 

 

//使用DemoController.cs: 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

 

//using 你的Respository;

 

using Microsoft.Practices.Unity;

 

public class DemoController : BaseController

{

    private IRDict _dictRepository;

    private IRStudent _studentRepository;

 

    public DemoController( IRDict aDictRespository, IRStudent aStudentRespository )

    {

        _dictRepository = aDictRespository;

        _studentRepository = aStudentRespository;

    }

}

 

 

 

上面的代码都是从公司封装的框架中提取出来,仅供大家分享。

 

由于Unity 已经包含在微软Enterprise Library 中,因此,只要下载安装Enterprise Library安装包即可。

 

其实我个人比较喜欢NInject 又小、又轻便,但由于特殊原因,实在是没有办法,上面这些代码很容易就改成NInject。

 

Unity的地址:http://entlib.codeplex.com/

 

NInject的地址:http://ninject.org/download

作者:老马快跑