zoukankan      html  css  js  c++  java
  • 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实例。

  • 相关阅读:
    【Java学习笔记十二】——初窥多线程
    【Java】使用swing实现简易计算器
    【Java学习技巧分享】——IDEA快捷键(超全!!!)
    【Java学习笔记九】——I/O流之字符流与数据流
    【Java学习笔记八】——I/O流之InputStream和OutputStream
    算法导论15章答案
    算法导论32章答案
    右击任务栏应用图标不显示菜单后的无奈美化
    verilog
    进制表示以及转换
  • 原文地址:https://www.cnblogs.com/majiang/p/2799404.html
Copyright © 2011-2022 走看看