欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET Web API Controller 是怎么建成的

程序员文章站 2022-07-01 15:10:57
此讯息管线架构图分为三层,由上至下,分别是装载(hosting)、讯息处理程序(message handlers)、以及控制器(controller)。图中的红色实心箭头代表 ht...
此讯息管线架构图分为三层,由上至下,分别是装载(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 对象就是这么建成的。