技术开发 频道

深入解读ASP.NET MVC 的依赖注入

    【IT168 技术文档】最近留意了一下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;
    }
}

 

0
相关文章