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

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

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

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

原因就出在覆盖 DefaultControllerFactoryGetControllerInstance 方法的实现上,当遇到不存的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

 

 

posted on 2010-10-12 14:24  老马快跑  阅读(9491)  评论(3编辑  收藏  举报