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实例。

原文地址:https://www.cnblogs.com/majiang/p/2799404.html