ASP.NET Web API WebHost宿主環境中管道、路由

ASP.NET Web API WebHost宿主環境中管道、路由

前言

上篇中說到ASP.NET Web API框架在SelfHost環境中管道、路由的一個形態,本篇就來講明一下在WebHost環境中ASP.NET Web API框架中的管道、路由又是哪種形態。web

 

ASP.NET Web API路由、管道

  • ASP.NET Web API 開篇介紹示例
  • ASP.NET Web API 路由對象介紹
  • ASP.NET Web API 管道模型
  • ASP.NET Web API selfhost宿主環境中管道、路由
  • ASP.NET Web API webhost宿主環境中管道、路由

 

ASP.NET Web API webhost宿主環境中管道、路由

下面將會主要講解路由的註冊執行過程(WebHost環境),對於管道不會去刻意的說明,都會包含在路由的講解中,拆開來講明效果不太好。api

 

HttpRoute->HostedHttpRoute->HttpWebRoute->Routeapp

想要清楚的瞭解路由的執行過程以及管道的形態,就必須對路由對象熟知,然而在前面的《ASP.NET Web API 路由對象介紹》篇幅中只是分別的對各個環境下的路由對象類型進行了說明,並無說明轉變的過程。框架

如今就來說解路由對象的「轉變」過程。ide

示例代碼1-1函數

        protected void Application_Start(object sender, EventArgs e)
        {
            GlobalConfiguration.Configuration.Routes.MapHttpRoute(
              "DefaultAPI", "api/{controller}/{id}", new { controller="product",id = RouteParameter.Optional });
        }

示例代碼1-1中是在WebHost環境下進行的路由註冊,根據MapHttpRoute()方法咱們轉定義過去應該是一個HttpRouteCollection類型的擴展方法類型HttpRouteCollectionExtensions,既然是HttpRouteCollectionExtensions類型裏的實現那咱們就過去看看到底啥狀況。this

示例代碼1-2spa

public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
        {
            if (routes == null)
            {
                throw System.Web.Http.Error.ArgumentNull("routes");
            }
            HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults);
            HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints);
            IDictionary<string, object> dataTokens = null;
            HttpMessageHandler handler2 = handler;
            IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);
            routes.Add(name, route);
            return route;
        }

咱們能夠看到返回類型是IHttpRoute,生成則是由HttpRouteCollection類型的實例調用其中的CreateRoute()方法來實現,這裏有的朋友要問了,這不是SelfHost中的路由註冊實現方式嗎?回答是對的,只不過在WebHost中利用多態來實現返回成其餘的類型,接着往下看。code

既然都看到了在這裏發生的變化,那說明是有繼承了HttpRouteCollection類型的這麼一個類型而後建立的路由對象。這樣一理就清晰多了,在SelfHost環境中HttpRouteCollection類型是存在於HttpConfiguration類型的對象中,並不單獨使用。而在WebHost中也是。server

這個時候咱們再回過頭來看一下代碼1-1中的GlobalConfiguration類型中的定義。

示例代碼1-3

        private static Lazy<HttpConfiguration> _configuration = new Lazy<HttpConfiguration>(delegate {
            HttpConfiguration configuration = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));
            configuration.Services.Replace(typeof(IAssembliesResolver), new WebHostAssembliesResolver());
            configuration.Services.Replace(typeof(IHttpControllerTypeResolver), new WebHostHttpControllerTypeResolver());
            configuration.Services.Replace(typeof(IHostBufferPolicySelector), new WebHostBufferPolicySelector());
            return configuration;
        });
        public static HttpConfiguration Configuration
        {
            get
            {
                return _configuration.Value;
            }
        }

從代碼1-3中咱們能夠看到_configuration靜態變量使用了延遲加載,啥意思呢就是下面的那個HttpConfiguration類型的Configuration屬性若是使用了纔會去實例化,跑偏了這不是重點。

重點是在實例化靜態變量_configuration中能夠清楚的看到使用了HostedHttpRouteCollection類型的路由集合類型對象做爲構造函數參數。能夠自行的去看一下HostedHttpRouteCollection的內部結構。

如今再回到建立路由的那會,也就是代碼1-1和代碼1-2中所示的那樣,實際也就是HostedHttpRouteCollection類型在建立路由對象,按照老規矩直接看實現代碼。

示例代碼1-4

    public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
    {
        return new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler);
    }

從代碼1-4中能夠清楚的看到是返回的是HostedHttpRoute路由對象,咱們能夠看一下構造函數,只有這樣才能知道「轉變」的過程。

    public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
    {
        RouteValueDictionary dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null;
        RouteValueDictionary dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null;
        RouteValueDictionary dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null;
        this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this);
        this.Handler = handler;
   }

在代碼1-4中咱們只須要關注OriginalRoute屬性的賦值,OriginalRoute屬性是HostedHttpRoute類型裏的一個屬性,是用來設置對Route對象的引用,示例代碼1-4中也就是HttpWebRoute類型的對象,對於HttpWebRoute對象的構造函數這裏就不例舉了。這個時候能夠看到是將HttpControllerRouteHandler類型的對象做爲Route(HttpWebRoute)對象的RouteHandler(路由處理程序)。

 

你們都知道ASP.NET Web API框架在WebHost環境中是依賴於ASP.NET的,實則也是經過IHttpModule來進行前期的消息攔截,下面咱們看一下在HttpModule中的代碼(我想應該是這樣的,若是有誤請指點。)

示例代碼1-5

    public class WebAPIHttpModule:IHttpModule
    {


        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public void Init(HttpApplication context)
        {
            context.PostResolveRequestCache += context_PostResolveRequestCache;
        }

        void context_PostResolveRequestCache(object sender, EventArgs e)
        {
            HttpApplication context = sender as HttpApplication;
            HttpContextWrapper contextWrapper = new HttpContextWrapper(context.Context);
            RouteData routeData = RouteTable.Routes.GetRouteData(contextWrapper);
            RequestContext requestContext=new RequestContext(contextWrapper,routeData);
            IHttpHandler httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext);
            IHttpAsyncHandler httpAsyncHandler = httpHandler as IHttpAsyncHandler;
            httpAsyncHandler.BeginProcessRequest(context.Context, null, null);
        }
     }

在代碼1-5中咱們能夠看到首先是獲取了RouteData對象實例,以此獲取RouteHandler,而後根據RequestContext獲取IHttpHandler,再轉換爲IHttpAsyncHandler類型的實例,而後調用其BeginProcessRequest()方法來執行操做。

上面這段話描述的是上述代碼的執行過程,有的朋友可能會疑問了,怎麼就獲取RouteData了?

這裏我給你們解釋一下,在咱們的代碼1-2中,有這樣的代碼:

            IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);
            routes.Add(name, route);

首先咱們看第一句,這裏的route上面說過了是HostedHttpRoute對象,這裏毫無疑問直接過,而後咱們再看第二句,這裏的routes是HostedHttpRouteCollection對象不假,可是這個Add()方法添加的方向不是HostedHttpRouteCollection,而是由咱們一開始在GlobalConfiguration類型中說過的RouteTable.Routes,當前環境是什麼?ASP.NET框架環境對吧!毫無疑問這個Add()方法把上面所說的route(HostedHttpRoute對象)添加到了當前環境的RouteTable.Routes中,有的朋友會問了類型不對。確實是不對的在添加的時候route(HostedHttpRoute對象)會轉換成HttpWebRoute對象,HttpWebRoute對象繼承自Route,能夠看前面的篇幅,想必說到這裏你們應該明白了。這裏我就很少說了。

 

咱們接着回到代碼1-5中,在獲取了RouteData以後經過RouteHandler的GetHttphandler()方法獲取IHttpHandler實例,在RouteData中的這個RouteHandler毫無疑問就是HttpControllerRouteHandler類型。

咱們來看下HttpControllerRouteHandler類型中的GetHttphandler()方法:

    protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new HttpControllerHandler(requestContext.RouteData);
    }

能夠看到是由HttpControllerHandler這個對象類型來執行最後的操做,那咱們就來看一下這個類型的定義:

public class HttpControllerHandler : IHttpAsyncHandler, IHttpHandler

如今你們明白爲何要轉成IHttpAsyncHandler了吧,由於若是調用了實現了IHttpHandler接口的函數是會報出異常的,由於在HttpControllerHandler類型中並無實現IHttpHandler接口只是一個空殼,而後咱們再看一下HttpControllerHandler類型的靜態構造函數:

圖1

 這個_server是Lazy<HttpMessageInvoker>類型,在BeginProcessRequest()方法中會執行SendAsync()以此進入ASP.NET Web API的管道。

 下面咱們看一下總體的一個示意圖,

圖2

 

最後對於HttpControllerDispatcher類型在控制器部分講解。

 

 

做者:金源

出處:http://www.cnblogs.com/jin-yuan/

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面

相關文章
相關標籤/搜索