ASP.NET MVC4学习笔记之Controller的激活
一. 高層相關類說明
當路由系統根據請求Url收集路由信息后,下一步就要將路由信息傳給Controller激活系統,Controller激活系統負責實現了IController接口的Controller類實例化。它的相關類族體系如下圖所示:
MvcHandler實現了IHttpHandler,?IHttpAsyncHandler,IRequiresSessionState三個接口,其中IHttpHandler,?IHttpAsyncHandler分別是HttpHandler同步與異步的實現,IRequiresSessionState是個標記接口,表示需要Session支持.?
IController, IAsyncController,?ControllerBase, Controller 是一個繼承體系,IController是控制器接口,只定義了一個方法Execute方法表示執行入口,
IAsyncController是控制器的異步執行版本,ControllerBase是控制器基類,為控制器執行做一些初始化和環境準備工作,實現了Execute方法并在其內調用保護的抽像方法ExecuteCore.這個地方應用了Templete Method模式.?Controller實現了一堆接口, 為我們編程提供方便,?定義了大量的屬性和方法,具體的后面章節專門講解.
IControllerFactory 表示的是控制器的創建工廠,其中定義了三個方法,?CreateController方法創建IController的實例,?GetControllerSessionBehavior方法獲取Controller的會話行為,我們可以在自定義的Controller的上應用SessionStateAttribute指定會話行為。ReleaseController負責釋放使用完的Controller實例。
public interface IControllerFactory
{
IController CreateController(RequestContext requestContext, string controllerName);
SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
void ReleaseController(IController controller);
}
ControllerBuilder 是負責實例化IController和IControllerFactory的接口,封裝具體的創建算法。提供了一個靜態只讀屬性Current表示當前的ControllerBuilder對象。
二. MvcHandler中IController與IControllerFactory的創建與執行
1. 主體過程ProcessRequest方法,代碼如下所示, 創建的過程委托給私有方法ProcessRequestInit
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}
?2.?ProcessRequestInit方法的主要代碼如下所示,我們可以看到最終的創建工作是交給了ControllerBuilder對象.
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
//其它代碼
// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(...)
}
}
?三.ControllerBuilder解析
1.接口定義如下:
public class ControllerBuilder
{
public ControllerBuilder();
public static ControllerBuilder Current { get; } ?//
public HashSet<string> DefaultNamespaces { get; } //默認命名空間,用于Controller類型解析過程
public IControllerFactory GetControllerFactory();?
public void SetControllerFactory(IControllerFactory controllerFactory); //設置自定義ControllerFactory
public void SetControllerFactory(Type controllerFactoryType); //設置自定義ControllerFactory的類型,?
}
ControllerBuilder主要封裝了IControllerFactory的創建過程,也許命名叫ControllerFactoryBuilder更合適,從接口可以看出,我們可以傳入自定義
實現的IControllerFactory。
2. 內部引用的幾個主要類說明:
IResolver<T> 只定義了一個泛型屬性,表示獲取相關類型的一個實例;
SingleServiceResolver<TService> 顧名思義,表示單一服務類型解析,它實現在了IResolver接口, 在ControllerBuilder內部使用的是SingleServiceResolver<IControllerFactory>;
DefaultControllerFactory 系統提供的默認的Controller創建工廠實現;
?3. 內部IControllerFactory創建過程
?在ControllerBuilder實例化時,調用默認構造函數,而默認構造函數調用如下的內部構造函數,serviceResolver傳值為null,
internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
{
_serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
() => _factoryThunk(),
new DefaultControllerFactory { ControllerBuilder = this },
"ControllerBuilder.GetControllerFactory");
}
_factoryTunk() 是一個返回IControllerFactory的委托(Func<IControllerFactory>),默認值是() => null; 其主要目的是當傳入自定義IControllerFactory時做統一處理,
public void SetControllerFactory(IControllerFactory controllerFactory)
{
_factoryThunk = () => controllerFactory;
}
ControllerBuilder返回IControllerFactory的方法內部實現如下:
public IControllerFactory GetControllerFactory()
{
return _serviceResolver.Current;
}
? ? 從上面的代碼中我們可以看出Factory的創建過程進一步委托給了SingleServiceResolver對象,現在我們看看SingleServiceResolver究竟是怎么創建對象的
四.SingleServiceResolver<TService> 類型
? SingleServiceResolver其實ASP.NET MVC許多基礎類型創建所遵詢的一個模式. 它的構造函數如下:
public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName)
{
//省略檢查代碼
_resolverThunk = () => DependencyResolver.Current; //??DependencyResolver.Current表示系統全局的對象解析器
_currentValueFromResolver = new Lazy<TService>(GetValueFromResolver); ?//從全局的Resolver器中創建對象
_currentValueThunk = currentValueThunk; //當前傳入的創建委托
_defaultValue = defaultValue; ? //默認值
_callerMethodName = callerMethodName;
}
返回實例的代碼如下
public TService Current
{
get { return _currentValueFromResolver.Value ?? _currentValueThunk() ?? _defaultValue; }
}
? ? ? 從中我們可以看出SingleServiceResolver解析對象的過程:
1. 首先從嘗試從全局的對象解析器(DependencyResolver)中創建對象
2. 否則嘗試利用當前的功能委托來創建對象
3. 最后返回對象的默認值
? ? 在IControllerFactory創建中,默認情況下第1種和第2種情況都不起作用,所以返回的是DefaultControllerFactory, 現在我們終于得到了IControllerFactory實例,現在來看看它是怎么生成Controller實例的。
五.DefaultControllerFactory解析
DefaultControllerFactory實現了IControllerFactory, 故名思義,它的主要作用就是Controller實例的創建與釋放,會話模式的獲取。
?1. Controller類型的實例化
Controller實例的創建實現在CreateController方法中,主要的代碼如下:
public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
//省略其它代碼
Type controllerType = GetControllerType(requestContext, controllerName);
IController controller = GetControllerInstance(requestContext, controllerType);
return controller;
}
可以看到分成了兩步走,首先查找確定Controller的類型,接著再利用類型創建其實例。下面來具體的看看相關的方法
1.1 Controller類型的查找
類型的查找實現在GetControllerType方法中,代碼如下:
protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)
{
// 省略其它代碼
//1. 首先檢查在定制路由規則時指定的命名空間
object routeNamespacesObj;
Type match;
if (requestContext != null && routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))
{
IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
if (routeNamespaces != null && routeNamespaces.Any())
{
HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceHash);
// the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"
if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))
{
// got a match or the route requested we stop looking
return match;
}
}
??}
// 檢查默認的命名空間
if (ControllerBuilder.DefaultNamespaces.Count > 0)
{
HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults);
if (match != null)
{
return match;
}
}
//檢查所有的命名空間,也就是只要有Controller名唯一匹配的就返回相應的Controller類型
return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);
}?
? ?這個方法是查找Controller類型的骨架,查找是由三個層次的命名空間組成,
1.首先從制定路由規則時指定的命名空間中查找,但一般我們指定路由規則時沒有指定命名空間,這里有還有一個參數UseNamespaceFallback表示是否查找后備命名空間,這個參數默認為true.?
? 2. 從默認的命名空間ControllerBuilder.DefaultNamespaces中查找
? 3. 從所有的命名空間中查找,查找唯一能匹配的Controller
? 在以上查找中,都會調用GetControllerTypeWithinNamespaces方法,現在來看看這個方法的實現
private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
{
// Once the master list of controllers has been created we can quickly index into it
ControllerTypeCache.EnsureInitialized(BuildManager);
ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
switch (matchingTypes.Count)
{
case 0:
// no matching types
return null;
case 1:
// single matching type
return matchingTypes.First();
default:
// multiple matching types
throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
}
?}
從以上的代碼中我們可以看到查找工作又進一步委托給了ControllerTypeCache這個內部類型,這個類型是特意為實現快速查找Controller類型而設計的一個數據結構,在內部它把所有的Controller通過反射把數據組織成如下形式:
controllerAName ? ? ?namespace1, ?Type
? ? ?namespace2, ? Type
controllerBName ? ? namespace1, ?Type
? ? ?namespace2, ? Type
? ...
當我們調用ControllerTypeCache.GetControllerTypes,傳入controllerName, namespaces參數時,首先會通過controllerName得到匹配的namespace和Type列表,
再利用傳入的namespaces參數與列表中的每個namespace進行比較,匹配則將相應的類型加入返回列表,如果傳入的namespaces為null, 則直接將列表中所有的類型都加入返回列表,在GetControllerTypeWithinNamespaces方法中我們檢查返回結果,如果只有一個類型,這是我們想要的結果,則直接返回,有一個以上則拋出Ambiguous異常。至此我們確定了Controller的類型,現在來看看Controller的實例化。
? ? 1.2 Controller類型的實例化
? 在前面我們已經看到,Controller類型實例化是實現在GetControllerInstance方法中,代碼如下:
protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
//省略非關鍵代碼
return ControllerActivator.Create(requestContext, controllerType);
}
直接調用了ControllerActivator來創建實例,ControllerActivator是一個類型為IControllerActivator的屬性,IControllerActivator的定義如下:
public interface IControllerActivator
{
IController Create(RequestContext requestContext, Type controllerType);
}
具體來看看ControllerActivator屬性的定義,
?private IControllerActivator ControllerActivator
{
get
{
if (_controllerActivator != null)
{
return _controllerActivator;
}
_controllerActivator = _activatorResolver.Current;
return _controllerActivator;
}
}
這里_controllerActivator在DefaultControllerFactory構造函數中初始化,代表傳入自定義的Controller激活器.具有最高的優先級。
_activatorResolver是IResolver<IControllerActivator>類型, 也是在構造函數中初始化,允許自定義實現IResolver<IControllerActivator>,具有第二高的優先級,
但在默認情況一下,前面兩個參數都為null,?_activatorResolver被實例化為SingleServiceResolver<IControllerActivator>類型。具體我們來看看DefaultControllerFactory的構造函數:
internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
{
if (controllerActivator != null)
{
_controllerActivator = controllerActivator;
}
else
{
_activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
() => null,
new DefaultControllerActivator(dependencyResolver),
"DefaultControllerFactory constructor");
}
}
SingleServiceResolver<T>泛型類前面已分析,這里不再贅述,從上面的代碼中我們看到,默認情況下Controller實例化最終落在了DefaultControllerActivator的頭上,
再來看看該類型的實現:
private class DefaultControllerActivator : IControllerActivator
{
private Func<IDependencyResolver> _resolverThunk;
public DefaultControllerActivator()
: this(null)
{
}
public DefaultControllerActivator(IDependencyResolver resolver)
{
if (resolver == null)
{
_resolverThunk = () => DependencyResolver.Current;
}
else
? {
_resolverThunk = () => resolver;
?}
? ?}
public IController Create(RequestContext requestContext, Type controllerType)
{
?try
?{
return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
}
catch (Exception ex)
{
throw new InvalidOperationException(...)
}
}
}
DefaultControllerActivator構造函數允許傳一個IDependencyResolver 對象,從上面的代碼中我們可以看出,優先使用該對象創建Conroller實例,
如果該對象為null,則嘗試使用系統默認的DependencyResolver,如果前面的兩者IDependencyResolver創建失敗,再使用Activator.CreateInstance實列化.
在默認情況一下,Controller實例是通過DependencyResolver.Current實列化,最終也是調用Activator.CreateInstance實例化的。
?2. Controller實例的釋放
釋放的實現代碼很簡單,即檢查Controller是否實現了IDisposable 接口,如果實現該接口則調用其Dispose()方法。
public virtual void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
3.Controller會話行為的設置
3.1 會話行為獲取
controller會話行為的獲取是通過反射得到應用在Controller上的SessionStateAttribute,具體的實現在代碼在GetControllerSessionBehavior中,
protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return SessionStateBehavior.Default;
}
return _sessionStateCache.GetOrAdd(
controllerType,
type =>
{
var attr = type.GetCustomAttributes(typeof(SessionStateAttribute), inherit: true)
.OfType<SessionStateAttribute>()
.FirstOrDefault();
return (attr != null) ? attr.Behavior : SessionStateBehavior.Default;
});
}
從上面的代碼中可以看出,如果沒在Controller上的指定特別的Session行為,會返回SessionStateBehavior.Default,表示由IHttpHandler實現的會話標記接口來確定會話行為,MvcHandler標記了IRequiresSessionState,表示Session可讀可寫.
3.2 會話行為設置
會話行為設置是在MvcRouteHandler中,具本的代碼如下:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
//設置會話行為
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}
protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
{
//省略非關鍵代碼
IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
}
六總結
在本小節中,我們在源代碼級別分析了ControllerFacotry和Controller實例的創建過程,從中可以看出ASP.NET MVC框架定義很多的擴展點,
? 下一節我們來看看具體Controller激活相關的擴展應用。
轉載于:https://www.cnblogs.com/jjyjjyjjy/p/3597647.html
總結
以上是生活随笔為你收集整理的ASP.NET MVC4学习笔记之Controller的激活的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: StandardContext
- 下一篇: 用Ghostscript API将PDF