Asp.net web Api源碼分析-如何獲取IHttpHandler


我們知道任何asp.net web程序的處理都是由IHttpHandler來實現的,那么這里我看看web api是如何讓獲取IHttpHandler的。這里假設你已經能熟練的使用web api,我還是沿用以前的風格以一個簡單的demo來說明吧。默認在我們的Global.asax.cs有這么一句

  WebApiConfig.Register(GlobalConfiguration.Configuration);而WebApiConfig.Register的默認實現也很簡單:

 public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

一看這個方法我們就知道這是在注冊一個路由信息,同時也提示我們以后自己開發asp.net mvc的時候,盡量把web api的路由分來處理,這里單獨放到WebApiConfig.Register來處理的。

首先我們還是來看看這里的HttpConfiguration是個什么東東,在GlobalConfiguration中有這么一句

HttpConfiguration config = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));

其中這里用到的HostedHttpRouteCollection、HttpConfiguration構造函數如下:

  private readonly RouteCollection _routeCollection;
        public HostedHttpRouteCollection(RouteCollection routeCollection)
        {
            if (routeCollection == null)
            {
                throw Error.ArgumentNull("routeCollection");
            }

            _routeCollection = routeCollection;
        }

  public HttpConfiguration(HttpRouteCollection routes)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            _routes = routes;
            Services = new DefaultServices(this);
            ParameterBindingRules = DefaultActionValueBinder.GetDefaultParameterBinders();

        }

到這里我們可以知道HttpConfiguration是可以操作路由的,里面有一個  public HttpRouteCollection Routes屬性。

現在我們來看看路由究竟是怎么添加的,MapHttpRoute方法具體實現如下:

 public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            HttpRouteValueDictionary defaultsDictionary = new HttpRouteValueDictionary(defaults);
            HttpRouteValueDictionary constraintsDictionary = new HttpRouteValueDictionary(constraints);
            IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: null, handler: handler);
            routes.Add(name, route);

            return route;
        }
    }

這里的routes是HostedHttpRouteCollection實例,其CreateRoute方法實現如下:

 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);
        }

其中HostedHttpRoute的構造函數如下:

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

HostedHttpRoute的OriginalRoute屬性有點特殊,是一個HttpWebRoute實例,HttpWebRoute的構造函數如下:

  internal class HttpWebRoute : Route

 public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler, IHttpRoute httpRoute)
            : base(url, defaults, constraints, dataTokens, routeHandler)
        {
            if (httpRoute == null)
            {
                throw Error.ArgumentNull("httpRoute");
            }

            HttpRoute = httpRoute;
        }

我們知道路由信息表里面的實例都是Route,看來這個的HttpWebRoute實例是我們真正需要的路由信息。這個路由處理的handler是 HttpControllerRouteHandler,其中HttpControllerRouteHandler實現了一個單例模式:

  public class HttpControllerRouteHandler : IRouteHandler
    {
        private static readonly Lazy<HttpControllerRouteHandler> _instance =
            new Lazy<HttpControllerRouteHandler>(() => new HttpControllerRouteHandler(), isThreadSafe: true);
     
         public static HttpControllerRouteHandler Instance
        {
            get { return _instance.Value; }
        }
     }

現在我們回到MapHttpRoute方法中來,這里已經獲取到了一個IHttpRoute的實例(HostedHttpRoute實例),現在剩下就只有一句了 routes.Add(name, route);,它的實現如下:

  public override void Add(string name, IHttpRoute route)
        {
            _routeCollection.Add(name, route.ToRoute());
        }

在HostedHttpRouteCollection的構造函數中曾把 _routeCollection設置為RouteTable.Routes,這里實際是在往RouteTable.Routes添加路由信息。這里的 route的IHttpRoute方法實現如下:

  public static Route ToRoute(this IHttpRoute httpRoute)
        {
            if (httpRoute == null)
            {
                throw Error.ArgumentNull("httpRoute");
            }

            HostedHttpRoute hostedHttpRoute = httpRoute as HostedHttpRoute;
            if (hostedHttpRoute != null)
            {
                return hostedHttpRoute.OriginalRoute;
            }


            return new HttpWebRoute(
                httpRoute.RouteTemplate,
                MakeRouteValueDictionary(httpRoute.Defaults),
                MakeRouteValueDictionary(httpRoute.Constraints),
                MakeRouteValueDictionary(httpRoute.DataTokens),
                HttpControllerRouteHandler.Instance,
                httpRoute);
        }
到這里我們應該知道web api 默認的Route其實就是HttpWebRoute,其對應的IRouteHandler默認是HttpControllerRouteHandler,至於程序是如何通過路由信息表來找到路由這里我們就忽略了,大家可以參考

asp.net mvc源碼分析-路由篇 如何找到 IHttpHandler
asp.net mvc源碼分析-Route的GetRouteData
找到了IRouteHandler那么后面就調用它的GetHttpHandler來獲取IHttpHandler實例,這里HttpControllerRouteHandler的GetHttpHandler實現非常簡單:

 return new HttpControllerHandler(requestContext.RouteData);

那么我們來看看HttpControllerHandler的構造函數:

 public class HttpControllerHandler : IHttpAsyncHandler

 public HttpControllerHandler(RouteData routeData)
        {
            if (routeData == null)
            {
                throw Error.ArgumentNull("routeData");
            }

            _routeData = new HostedHttpRouteData(routeData);

        }
而HostedHttpRouteData的構造函數如下:

  public HostedHttpRouteData(RouteData routeData)
        {
            if (routeData == null)
            {
                throw Error.ArgumentNull("routeData");
            }

            OriginalRouteData = routeData;

            HttpWebRoute route = routeData.Route as HttpWebRoute;
            Route = route == null ? null : route.HttpRoute;

        }

至於這里的HostedHttpRoute 為什么需要一個OriginalRoute ,HostedHttpRouteData 需要一個OriginalRouteData 屬性,在這里我就不多說了吧,相信大家應該都知道他們的作用吧,在后面需要的地方我再說說這2個屬性干什么東東了。

這里我們還是總結一下吧:web api默認的路由都是在WebApiConfig.Register方法中添加,默認的route是HttpWebRoute實例,默認的 IRouteHandler是HttpControllerRouteHandler實例,它返回的handler是一個實現 IHttpAsyncHandler接口HttpControllerHandler實例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM