此讯息管线架构图分为三层,由上至下,分别是装载(hosting)、讯息处理程序(message handlers)、以及控制器(controller)。图中的红色实心箭头代表 http 请求讯息,虚线箭头代表 http 响应消息。讯息处理流程如下:

 

当客户端对服务器发出的 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 对象就是这么建成的。