ASP.NET Web API Controller 是怎么建成的
当客户端对服务器发出的 http 请求开始进入 asp.net web api 框架时,该 http 请求讯息会被包装成httprequestmessage对象,并且进入图中最顶端「装载」方块的httpserver(web 装载)或httpselfhostserver(自我装载)。接着该讯息便流入管线的下一个阶段,直到整个讯息流程处理完毕,会得到一个代表 http 响应消息的 httpresponsemessage对象,并将此对象的讯息内容传回客户端。
httprequestmessage对象进入「讯息处理程序」管线。在此阶段,http 讯息行经数个讯息处理程序(message handlers),并且在返回 http 响应消息时以相反的顺序执行。
在各个讯息处理程序之后,http 请求讯息接着会传递给httpcontrollerdispatcher,并且由这个对象来建立 web api controller,然后将 http 请求传递给 controller 对象(图中标示「(a) 建立 controller」的步骤)。
controller 会先决定目标动作方法(即图中标示「(b) 选择 action」的步骤),然后呼叫它。动作方法将负责产生响应内容,之后便依前述管线流程的反方向沿路返回。
以上便是 web api http 讯息管线的大致处理流程。
web api controller 是怎样建成的?
刚才只说明了 web api http 讯息管线的大致处理流程,而欲注入相依对象至 controller 类别的建构函式,或从中动些手脚来改变预设行为,必得了解 web api 框架建立 controller 的内部过程。本节将进一步说明其中的复杂环节,其中会反复提及多个抽象接口,第一次时可能略感吃力,并难免心生疑惑,但等到实际写过、跑过一遍后面的范例程序,再回头来看这一节的说明,整个拼图应该就会渐渐明朗了。
刚才提到,httpcontrollerdispatcher会建立目标 controller 对象,亦即先前 asp.net web
api 管线架构图中标示「(a) 建立 controller」的步骤。此步骤其实包含两件工作:
解析目标 controller。亦即决定该使用哪一个 controller 类别。
建立目标 controller 类别的实例,并将 http 请求(httprequestmessage对象)传递给它,以便由 controller 进行后续处理。
首先,「解析目标 controller」的工作主要是从应用程序的 dll 中寻找所有可用的 controller 类别,再从中选择一个与当前 http request 匹配的。其处理逻辑如下图所示:
说明:
图中下方的iassembliesresolver对象的getassemblies方法将提供应用程序的组件列表,并由ihttpcontrollertyperesolver对象的getcontrollertypes方法取得可用的 controller 类别清单。
ihttpcontrollerselector负责决定要选择哪一个 controller 类别,然后返回一个包含其型别信息的httpcontrollerdescriptor对象给httpcontrollerdispatcher。
从确定目标 controller 型别之后,到建立完成 controller 实例的过程中,还有经过一些核心标准接口所提供的扩充点。底下再用一张 uml 活动图搭配 web api 原始码的方式来解构其内部处理过程。
说明如下(与上图中的数字编号对应):
(1) httpcontrollerdispatcher透过ihttpcontrollerselector对象的selectcontroller方法来取得目标 controller 型别信息,这型别信息是包在一个httpcontrollerdescriptor 对象里。
(2) httpcontrollerdispatcher接着呼叫httpcontrollerdescriptor对象的createcontroller 方法,而该方法又会去呼叫servicescontainer对象的gethttpcontrolleractivator方法来取得ihttpcontrolleractivator对象。以下程序片段摘自 web api 原始码,涵盖了此步骤至下一步骤的部分逻辑:
复制代码
// httpcontrollerdescriptor 类别的 createcontroller 方法。
public virtual ihttpcontroller createcontroller(httprequestmessage request)
{
ihttpcontrolleractivator activator = configuration.services.gethttpcontrolleractivator();
ihttpcontroller instance = activator.create(request, this, controllertype);
return instance;
}
复制代码
(3) 取得ihttpcontrolleractivator对象之后,便接着呼叫它的create方法,而此方法会呼叫自己的getinstanceoractivator方法,以便取得 controller 实例。以下程序片段摘自defaulthttpcontrolleractivator类别的原始码,我把错误处理以及快取机制的部分拿掉,并加上了中文批注:
复制代码
// defaulthttpcontrolleractivator 類別的 create 方法(重點摘錄)
public ihttpcontroller create(httprequestmessage request,
httpcontrollerdescriptor controllerdescriptor, type controllertype)
{
func<ihttpcontroller> activator;
ihttpcontroller controller =
getinstanceoractivator(request, controllertype, out activator);
if (controller != null)
{
// 註冊至 web api 框架的 dependency resolver
// 已經建立此 controller 型別的執行個體。
return controller; // 那就直接使用此物件。
}
// 目標 controller 物件尚未建立
return activator(); // 那就用 getinstanceoractivator 方法傳回的委派來建立物件
}
复制代码
(4) ihttpcontrolleractivator对象的getinstanceoractivator方法会呼叫httprequestmessage 的扩充方法getdependencyscope来取得与当前 request 关联的idependencyscope对象
(其实就是个 service locator),并利用它的getservice方法来取得 controller 对象。若 getservice方法并未传回 controller 对象,而是传回null(代表无法解析服务型别),则退而求其次,改用型别反射(reflection)机制来建立 controller 对象。一样搭配原始码来看:
复制代码
// 摘自 defaulthttpcontrolleractivator.cs
private static ihttpcontroller getinstanceoractivator(httprequestmessage request, type controllertype, out func<ihttpcontroller>> activator)
{
// 若 dependency scope 有传回 controller 对象,便使用它。
ihttpcontroller instance = (ihttpcontroller)request.getdependencyscope().getservice(controllertype);
if (instance != null)
{
activator = null;
return instance;
}
// 否则,建立一个委派来创建此型别的实例。
activator = typeactivator.create<ihttpcontroller>(controllertype);
return null;
}
复制代码
其中的request.getdependencyscope()就是对应到刚才说的「呼叫httprequestmessage 的扩充方法 getdependencyscope 来取得与当前 request 关联的 idependencyscope 对象。」而这里实际取得的idependencyscope对象会是 web api 框架提供的预设实作: emptyresolver。从类别名称可知,这类别其实啥事也没做——它的getservice方法一律传回null。因此,在预设情况下,web api 框架会一律使用型别反射(reflection)机制来建立 controller 对象,而这也就是为什么我们的 controller 类别一定要有预设建构函式(default constructor)的缘故。
大致上,controller 对象就是这么建成的。
上一篇: android (四)手势