• ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道


       Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样的。

      简单的概括起来,Web Host模式下的ASP.NET Web API在Web应用中注册的路由(HostedHttpRoute)最终会转换成ASP.NET 全局路由表中的Route(HttpWebRoute),ASP.NET路由系统会对请求进行匹配,把匹配的路由变量数据存放到RequestContext中,再通过UrlRoutingModule从匹配的Route(从RequestContext中获取,见ASP.NET路由部分代码)中获取IRouteHandler,即HttpControllerRouteHandler,其提供的HttpControllerHandler最终会创建出消息处理管道,即触发HttpServer,消息处理管道的第一个消息处理器。

    一、涉及的类及源码分析 

       Web Host 模式下的类基本都在System.Web.Http.WebHost程序集中,相比Web API的接口基本都在System.Web.Http程序集中,包括GlobalConfiguration和HttpConfiguration类,主要类和成员如下图:

      

      简要说明:

      在静态类GlobalConfiguration中创建了HttpConfiguration对象,其构造参数默认指定为HostedHttpRouteCollection,而该集合的构造函数指定为RouteCollection类型的ASP.NET 路由系统全局路由表,通过组合方式对其进行了封装,将其作为HostedHttpRouteCollection的一个属性,用来存放ASP.NET 路由中的Route对象,路由注册时加入路由表中的路由对象HostedHttpRoute最终都要转换成Route对象。

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

      而HostedHttpRouteCollection继承自HttpRouteCollection,在其重写的CreateRoute方法中,创建的是一个HostedHttpRoute路由对象

      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对象时候,在构造函数中,直接创建HttpWebRoute对象,并直接指定IRouteHandler为HttpControllerRouteHandler

      OriginalRoute = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance, this);

      而HttpWebRoute直接继承自Route,所以本质上还是利用了ASP.NET路由的功能。

      另外,HttpControllerRouteHandler其方法GetHttpHandler默认返回的是HttpControllerHandler,也是直接指定

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

      在其构造函数中,默认传入了GlobalConfiguration.DefaultServer,其在GlobalConfiguration中指定的是HttpServer,其是ASP.NET Web API 消息处理管道的第一个处理器(HttpMessageHandler)

      public HttpControllerHandler(RouteData routeData)
      : this(routeData, GlobalConfiguration.DefaultServer)
      {
      }

      HttpControllerHandler是一个HttpHandler

       public class HttpControllerHandler : HttpTaskAsyncHandler

       public abstract class HttpTaskAsyncHandler : IHttpAsyncHandler, IHttpHandler

       在其ProcessRequestAsync方法中通过以下语句将请求转接入消息处理管道中。

      response = await _server.SendAsync(request, cancellationToken)

    1、HttpWebRoute 

      HttpWebRoute 类直接继承ASP.NET路由中的Route,重写了主要方法GetRouteData、GetVirtualPath和ProcessConstraint,其主要功能还是调用基类的同名方法(如base.GetRouteData),另外,还有个HttpRoute属性,其是创建它的HostedHttpRoute对象,简要说明中已有描述,后边也会再次指出,约束检查还是用IHttpRouteConstraint。

      可知,HttpWebRoute 是Web Host模式下ASP.NET Web API实际执行路由功能的对象,而其实际又使用(继承)了ASP.NET路由系统的Route对象来实现的,实现了ASP.NET Web API路由功能和ASP.NET路由的链接。另外,HttpWebRoute对象是通过HostedHttpRoute对象创建的。

      总结下来它是对ASP.NET路由系统中Route对象封装。

      //继承ASP.NET路由的Route

      internal class HttpWebRoute : Route
      {
        internal const string HttpRouteKey = "httproute";

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

        //创建它的IHttpRoute 即HostedHttpRoute
        public IHttpRoute HttpRoute { get; private set; }

        //重写了约束检查处理功能,优先使用IHttpRouteConstraint

        //注意请求是HttpContextBase类型的HttpContext,在ASP.NET路由中参数用得是HttpContextBase类型而不是HttpRequestMessage类型

        protected override bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection       routeDirection)
        {
          ValidateConstraint(HttpRoute.RouteTemplate, parameterName, constraint);

          IHttpRouteConstraint httpRouteConstraint = constraint as IHttpRouteConstraint;
          if (httpRouteConstraint != null)
          {

            //如果是IHttpRouteConstraint

            //创建一个HttpRequestMessage 
            HttpRequestMessage request = httpContext.GetOrCreateHttpRequestMessage();
            return httpRouteConstraint.Match(request, HttpRoute, parameterName, values, ConvertRouteDirection(routeDirection));
          }

          //不是的话,调用基类ASP.NET路由对应检查功能

          return base.ProcessConstraint(httpContext, constraint, parameterName, values, routeDirection);
        }

        //重写了路由解析功能,注意参数也是HttpContextBase 

        //注意返回值都是ASP.NET路由中的数据对象RouteData

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
          try
          {
            if (HttpRoute is HostedHttpRoute)
            {

              //Web Host模式下,就调用基类ASP.NET路由对应的功能
              return base.GetRouteData(httpContext);
            }
            else
            {

              //其他情况就调用,创建本对象的HttpRoute自身的功能,也要构建HttpRequestMessage 
              HttpRequestMessage request = httpContext.GetOrCreateHttpRequestMessage();
              IHttpRouteData data = HttpRoute.GetRouteData(httpContext.Request.ApplicationPath, request);
              return data == null ? null : data.ToRouteData();
            }
          }
          catch (Exception exception)
          {
            ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(exception);
            return new RouteData(this, new HttpRouteExceptionRouteHandler(exceptionInfo));
          }
        }

        //重写了生成URL功能,主要逻辑和GetRouteData情况一样

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
          if (!values.ContainsKey(HttpRouteKey))
          {
            return null;
          }

          RouteValueDictionary newValues = GetRouteDictionaryWithoutHttpRouteKey(values);

          if (HttpRoute is HostedHttpRoute)
          {
            return base.GetVirtualPath(requestContext, newValues);
          }
          else
          {
            HttpRequestMessage request = requestContext.HttpContext.GetOrCreateHttpRequestMessage();
            IHttpVirtualPathData virtualPathData = HttpRoute.GetVirtualPath(request, values);

            return virtualPathData == null ? null : new VirtualPathData(this, virtualPathData.VirtualPath);
          }
        }

        private static RouteValueDictionary GetRouteDictionaryWithoutHttpRouteKey(IDictionary<string, object> routeValues)
        {
          var newRouteValues = new RouteValueDictionary();
          foreach (var routeValue in routeValues)
          {
            if (!String.Equals(routeValue.Key, HttpRouteKey, StringComparison.OrdinalIgnoreCase))
            {
              newRouteValues.Add(routeValue.Key, routeValue.Value);
            }
          }
          return newRouteValues;
        }

        private static HttpRouteDirection ConvertRouteDirection(RouteDirection routeDirection)
        {
          if (routeDirection == RouteDirection.IncomingRequest)
          {
            return HttpRouteDirection.UriResolution;
          }

          if (routeDirection == RouteDirection.UrlGeneration)
          {
            return HttpRouteDirection.UriGeneration;
          }

          throw Error.InvalidEnumArgument("routeDirection", (int)routeDirection, typeof(RouteDirection));
        }

        internal static void ValidateConstraint(string routeTemplate, string name, object constraint)
        {
          if (constraint is IHttpRouteConstraint)
          {
            return;
          }

          if (constraint is IRouteConstraint)
          {
            return;
          }

          if (constraint is string)
          {
            return;
          }

          throw CreateInvalidConstraintTypeException(routeTemplate, name);
        }

        private static Exception CreateInvalidConstraintTypeException(string routeTemplate, string name)
        {
          return Error.InvalidOperation(
            SRResources.Route_ValidationMustBeStringOrCustomConstraint,
            name,
            routeTemplate,
            typeof(IHttpRouteConstraint).FullName,
            typeof(IRouteConstraint).FullName);
        }
      }

    2、HostedHttpRoute

       HostedHttpRoute是全局路由表(HostedHttpRouteCollection)创建路由(调用CreateRoute方法)时候创建的对象,并将其添加到路由表中,在其构造函数中创建了一个HttpWebRoute(真正实施路由的对象,即1、HttpWebRoute)对象的OriginalRoute 属性,从前边得知HttpWebRoute继承Route,相当于是对ASP.NET 路由功能的间接封装。

      另外,该类实现了HttpRoute接口,其中的GetRouteData、GetVirtualPath参数的去求上下文信息是之前保存在HttpRequestMessage的属性字典中,KEY值为MS_HttpContext,因为ASP.NET 路由中对应方法是用HttpContext的,而不是HttpRequestMessage,所以需要从其字典属性中去取对应请求上下文数据。

      总结下来它是对ASP.NET路由系统中Route对象间接封装。

      internal class HostedHttpRoute : IHttpRoute
      {
        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;

          //直接创建HttpWebRoute,保存到OriginalRoute 属性,同时指定了HttpControllerRouteHandler作为IRouteHandler
          OriginalRoute = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance, this);
          Handler = handler;
        }

        public string RouteTemplate
        {
          get { return OriginalRoute.Url; }
        }

        public IDictionary<string, object> Defaults
        {
          get { return OriginalRoute.Defaults; }
        }

        public IDictionary<string, object> Constraints
        {
          get { return OriginalRoute.Constraints; }
        }

        public IDictionary<string, object> DataTokens
        {
          get { return OriginalRoute.DataTokens; }
        }

        public HttpMessageHandler Handler { get; private set; }

        internal Route OriginalRoute { get; private set; }

        //实现了接口的GetRouteData

        public IHttpRouteData GetRouteData(string rootVirtualPath, HttpRequestMessage request)
        {
          if (rootVirtualPath == null)
          {
            throw Error.ArgumentNull("rootVirtualPath");
          }

          if (request == null)
          {
            throw Error.ArgumentNull("request");
          }

          //从HttpRequestMessage字典属性中获取Key为MS_HttpContext的上下文数据

          HttpContextBase httpContextBase = request.GetHttpContext();
          if (httpContextBase == null)
          {
            httpContextBase = new HttpRequestMessageContextWrapper(rootVirtualPath, request);
          }

          //通过OriginalRoute属性的同名方法调用ASP.NET路由的同名方法,并把上下文数据作为参数

          RouteData routeData = OriginalRoute.GetRouteData(httpContextBase);
          if (routeData != null)
          {

            //对返回的ASP.NET 路由数据RouteData封装成HostedHttpRouteData
            return new HostedHttpRouteData(routeData);
          }

          return null;
        }

        public IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values)
        {
          if (request == null)
          {
            throw Error.ArgumentNull("request");
          }

          //从HttpRequestMessage字典属性中获取Key为MS_HttpContext的上下文数据

          HttpContextBase httpContextBase = request.GetHttpContext();
          if (httpContextBase != null)
          {

            //还要从HttpRequestMessage中获取对应解析好的路由数据
            HostedHttpRouteData routeData = request.GetRouteData() as HostedHttpRouteData;
            if (routeData != null)
            {

              //构建出一个RequestContext 对象,其封装了httpContextBase和routeData .OriginalRouteData(即RouteData)
              RequestContext requestContext = new RequestContext(httpContextBase, routeData.OriginalRouteData);

              //通过OriginalRoute调用ASP.NET路由系统的同名方法,并以RequestContext 作为参数
              VirtualPathData virtualPathData = OriginalRoute.GetVirtualPath(requestContext, new RouteValueDictionary(values));
              if (virtualPathData != null)
              {

                //封装成HostedHttpVirtualPathData,routeData.Route为HttpWebRoute
                return new HostedHttpVirtualPathData(virtualPathData, routeData.Route);
              }
            }
          }

          return null;
        }
      }

    3、HostedHttpRouteData 

      是对ASP.NET路由中RouteData 的封装,其属性OriginalRouteData保存了被封装的RouteData,被封装的RouteData(即OriginalRouteData)的Route属性是HttpWebRoute。

      internal class HostedHttpRouteData : IHttpRouteData
      {
        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;
        }

        public IHttpRoute Route { get; private set; }

        public IDictionary<string, object> Values
        {
          get { return OriginalRouteData.Values; }
        }

        internal RouteData OriginalRouteData { get; private set; }
      }

    4、HostedHttpVirtualPathData 

      是对ASP.NET路由中VirtualPathData 的封装,返回的VirtualPath就是对应被封装的VirtualPathData 的VirtualPath属性

      internal class HostedHttpVirtualPathData : IHttpVirtualPathData
      {
        private readonly VirtualPathData _virtualPath;

        public HostedHttpVirtualPathData(VirtualPathData virtualPath, IHttpRoute httpRoute)
        {
          if (virtualPath == null)
          {
            throw Error.ArgumentNull("route");
          }

          _virtualPath = virtualPath;
          Route = httpRoute;
        }

        public IHttpRoute Route { get; private set; }

        public string VirtualPath
        {
          get { return _virtualPath.VirtualPath; }
          set
          {
            if (value == null)
            {
              throw Error.PropertyNull();
            }
            _virtualPath.VirtualPath = value;
          }
        }
      }

    5、HostedHttpRouteCollection 

      是Web Host模式下的全局路由表,由GlobalConfiguration类构建HttpConfiguration对象时候,在构造函数中默认指定,在创建对象HostedHttpRouteCollection 本身时候,在构造函数中,又指定了一个ASP.NET路由的路由表RouteTable.Routes,其用来真正保存最后的路由对象Route,路由注册时候创建的对象,最终都要转换成Route,并存放到ASP.NET路由的路由表RouteTable.Routes中,其类型为RouteCollection ,GlobalConfiguration中有下边这么一句,都是默认写死的

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

      简要说明中已经说过,后边还会说明。

      另外,其继承自HttpRouteCollection,重写其主要方法,GetRouteData和GetVirtualPath方法内部调用的是内部路由表RouteTable.Routes类型为RouteCollection的对应同名方法。

      注册路由时候,HttpRouteCollection定义了扩展方法MapHttpRoute,其内部分别调用了CreateRoute和Add方法,来完成注册,如下代码片段

      //先创建建路由
      IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: null, handler: handler);

      //再往路由表里添加路由
      routes.Add(name, route);

      由于扩展方法有继承性,扩展一个类型的时候,其也扩展了派生类,所以实际是调用HostedHttpRouteCollection对应CreateRoute和Add方法。

      总结下来它是对ASP.NET全局路由表的封装,通过组合方式

      internal class HostedHttpRouteCollection : HttpRouteCollection
      {
        private readonly RouteCollection _routeCollection;
        private readonly string _virtualPathRoot;

        public HostedHttpRouteCollection(RouteCollection routeCollection)
          : this(routeCollection, virtualPathRoot: null)
        {
        }

        public HostedHttpRouteCollection(RouteCollection routeCollection, string virtualPathRoot)
        {
          if (routeCollection == null)
          {
            throw Error.ArgumentNull("routeCollection");
          }

          _routeCollection = routeCollection;
          _virtualPathRoot = virtualPathRoot;
        }

        public override string VirtualPathRoot
        {
          get
          {
            if (_virtualPathRoot == null)
            {
              return HostingEnvironment.ApplicationVirtualPath;
            }
            else
            {
              return _virtualPathRoot;
            }
          }
        }

        public override int Count
        {
          get { return _routeCollection.Count; }
        }


        public override IHttpRoute this[string name]
        {
          get
          {
            HttpWebRoute route = _routeCollection[name] as HttpWebRoute;
            if (route != null)
            {
              return route.HttpRoute;
            }

            throw Error.KeyNotFound();
          }
        }


        public override IHttpRoute this[int index]
        {
          get
          {
            HttpWebRoute route = _routeCollection[index] as HttpWebRoute;
            if (route != null)
            {
              return route.HttpRoute;
            }

            throw Error.ArgumentOutOfRange("index", index, SRResources.RouteCollectionOutOfRange);
          }
        }


        public override IHttpRouteData GetRouteData(HttpRequestMessage request)
        {
          if (request == null)
          {
            throw Error.ArgumentNull("request");
          }

          HttpContextBase httpContextBase = request.GetHttpContext();
          if (httpContextBase == null)
          {
            httpContextBase = new HttpRequestMessageContextWrapper(VirtualPathRoot, request);
          }

          if (httpContextBase.GetHttpRequestMessage() == null)
          {
            httpContextBase.SetHttpRequestMessage(request);
          }

          //调用内部ASP.NET路由的全局路由表对应方法

          RouteData routeData = _routeCollection.GetRouteData(httpContextBase);

          if (routeData != null && !(routeData.RouteHandler is System.Web.Routing.StopRoutingHandler))
          {

            //返回HostedHttpRouteData,返回结果的声明是IHttpRouteData
            return new HostedHttpRouteData(routeData);
          }

          return null;
        }


        public override IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, string name, IDictionary<string, object> values)
        {
          if (request == null)
          {
            throw Error.ArgumentNull("request");
          }

          HttpContextBase httpContextBase = request.GetHttpContext();
          if (httpContextBase == null)
          {
            httpContextBase = new HttpRequestMessageContextWrapper(VirtualPathRoot, request);
          }

          if (httpContextBase.GetHttpRequestMessage() == null)
          {
            httpContextBase.SetHttpRequestMessage(request);
          }

          IHttpRouteData routeData = request.GetRouteData();
          if (routeData == null)
          {
            return null;
          }

          RequestContext requestContext = new RequestContext(httpContextBase, routeData.ToRouteData());
          RouteValueDictionary routeValues = values != null ? new RouteValueDictionary(values) : new RouteValueDictionary();

          //调用内部ASP.NET路由的全局路由表对应方法
          VirtualPathData virtualPathData = _routeCollection.GetVirtualPath(requestContext, name, routeValues);

          if (virtualPathData != null)
          {
            if (!(virtualPathData.Route is HttpWebRoute))
            {
              if (routeValues.Remove(HttpWebRoute.HttpRouteKey))
              {
                VirtualPathData virtualPathDataWithoutHttpRouteValue = _routeCollection.GetVirtualPath(requestContext, name, routeValues);
                if (virtualPathDataWithoutHttpRouteValue != null)
                {
                  virtualPathData = virtualPathDataWithoutHttpRouteValue;
                }
              }
            }

            //返回HostedHttpVirtualPathData,返回结果的声明是IHttpVirtualPathData 

            return new HostedHttpVirtualPathData(virtualPathData, routeData.Route);
          }

          return null;
        }

        //路由映射时候创建路由
        public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object>       dataTokens, HttpMessageHandler handler)
        {
          if (constraints != null)
          {
            foreach (var constraint in constraints)
            {
              ValidateConstraint(uriTemplate, constraint.Key, constraint.Value);
            }
          }

          //每次创建的是这个路由对象,内部创建了一个继承自Route的HttpWebRoute对象

          return new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler);
        }


        protected override void ValidateConstraint(string routeTemplate, string name, object constraint)
        {
          HttpWebRoute.ValidateConstraint(routeTemplate, name, constraint);
        }

        //添加一个路由对象

        public override void Add(string name, IHttpRoute route)
        {

          //往内部ASP.NET路由系统全局路由表添加Route对象,通过ToRoute方法转换
          _routeCollection.Add(name, route.ToRoute());
        }


        public override void Clear()
        {
          _routeCollection.Clear();
        }


        public override bool Contains(IHttpRoute item)
        {
          foreach (RouteBase route in _routeCollection)
          {
            HttpWebRoute webRoute = route as HttpWebRoute;
            if (webRoute != null && webRoute.HttpRoute == item)
            {
              return true;
            }
          }

          return false;
        }

        public override bool ContainsKey(string name)
        {
          return _routeCollection[name] != null;
        }

        public override IEnumerator<IHttpRoute> GetEnumerator()
        {
          return _routeCollection
          .OfType<HttpWebRoute>()
          .Select(httpWebRoute => httpWebRoute.HttpRoute)
          .GetEnumerator();
        }


        public override bool TryGetValue(string name, out IHttpRoute route)
        {
          HttpWebRoute rt = _routeCollection[name] as HttpWebRoute;
          if (rt != null)
          {
            route = rt.HttpRoute;
            return true;
          }

          route = null;
          return false;
        }

        private static NotSupportedException NotSupportedByRouteCollection()
        {
          return Error.NotSupported(SRResources.RouteCollectionNotSupported, typeof(HostedHttpRouteCollection).Name);
        }

        private static NotSupportedException NotSupportedByHostedRouteCollection()
        {
          return Error.NotSupported(SRResources.RouteCollectionUseDirectly, typeof(RouteCollection).Name);
        }
      }

    6、GlobalConfiguration

      public static class GlobalConfiguration
      {
        private static Lazy<HttpConfiguration> _configuration = CreateConfiguration();

        private static Lazy<HttpMessageHandler> _defaultHandler = CreateDefaultHandler();

        private static Lazy<HttpServer> _defaultServer = CreateDefaultServer();


        public static HttpConfiguration Configuration
        {
          get { return _configuration.Value; }
        }


        public static HttpMessageHandler DefaultHandler
        {
          get { return _defaultHandler.Value; }
        }

        public static HttpServer DefaultServer
        {
          get { return _defaultServer.Value; }
        }

        public static void Configure(Action<HttpConfiguration> configurationCallback)
        {
          if (configurationCallback == null)
          {
            throw new ArgumentNullException("configurationCallback");
          }

          configurationCallback.Invoke(Configuration);
          Configuration.EnsureInitialized();
        }

        internal static void Reset()
        {
          _configuration = CreateConfiguration();
          _defaultHandler = CreateDefaultHandler();
          _defaultServer = CreateDefaultServer();
        }

        private static Lazy<HttpConfiguration> CreateConfiguration()
        {
          return new Lazy<HttpConfiguration>(() =>
          {

           //默认指定,HostedHttpRouteCollection,并传入ASP.NET路由系统的全局路由表
            HttpConfiguration config = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));
            ServicesContainer services = config.Services;
            Contract.Assert(services != null);
            services.Replace(typeof(IAssembliesResolver), new WebHostAssembliesResolver());
            services.Replace(typeof(IHttpControllerTypeResolver), new WebHostHttpControllerTypeResolver());
            services.Replace(typeof(IHostBufferPolicySelector), new WebHostBufferPolicySelector());
            services.Replace(typeof(IExceptionHandler),
            new WebHostExceptionHandler(services.GetExceptionHandler()));
            return config;
          });
        }

        private static Lazy<HttpMessageHandler> CreateDefaultHandler()
        {
          return new Lazy<HttpMessageHandler>(() => new HttpRoutingDispatcher(_configuration.Value));
        }

        //默认指定第一个HttpMessageHandler

        private static Lazy<HttpServer> CreateDefaultServer()
        {
          return new Lazy<HttpServer>(() => new HttpServer(_configuration.Value, _defaultHandler.Value));
        }

      }

    7、HttpControllerRouteHandler 

      在HostedHttpRoute构造函数中创建HttpWebRoute对象时候,已经直接指定每个请求路由匹配后使用的IRouteHandler,其返回的IHttpHandler 用来处理请求。

      OriginalRoute = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance, this);

      public class HttpControllerRouteHandler : IRouteHandler
      {
        private static readonly Lazy<HttpControllerRouteHandler> _instance =
          new Lazy<HttpControllerRouteHandler>(() => new HttpControllerRouteHandler(), isThreadSafe: true);

        protected HttpControllerRouteHandler()
        {
        }

        public static HttpControllerRouteHandler Instance
        {
          get { return _instance.Value; }
        }

        IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
        {
          return GetHttpHandler(requestContext);
        }

        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
        {

         //直接new了HttpControllerHandler
          return new HttpControllerHandler(requestContext.RouteData);
        }
      }

    8、HttpControllerHandler 

      public class HttpControllerHandler : HttpTaskAsyncHandler
      {
        internal static readonly string OwinEnvironmentHttpContextKey = "owin.Environment";

        internal static readonly string OwinEnvironmentKey = "MS_OwinEnvironment";

        private static readonly Lazy<Action<HttpContextBase>> _suppressRedirectAction =
          new Lazy<Action<HttpContextBase>>(
            () =>
            {
              if (!SuppressFormsAuthRedirectHelper.GetEnabled(WebConfigurationManager.AppSettings))
              {
                return httpContext => { };
              }

              return httpContext => httpContext.Response.SuppressFormsAuthenticationRedirect = true;
            });

        private static readonly Lazy<IHostBufferPolicySelector> _bufferPolicySelector =
          new Lazy<IHostBufferPolicySelector>(() => GlobalConfiguration.Configuration.Services.GetHostBufferPolicySelector());

        private static readonly Lazy<IExceptionHandler> _exceptionHandler = new Lazy<IExceptionHandler>(() =>
          ExceptionServices.GetHandler(GlobalConfiguration.Configuration));
        private static readonly Lazy<IExceptionLogger> _exceptionLogger = new Lazy<IExceptionLogger>(() =>
          ExceptionServices.GetLogger(GlobalConfiguration.Configuration));

        private static readonly Func<HttpRequestMessage, X509Certificate2> _retrieveClientCertificate = new Func<HttpRequestMessage, X509Certificate2>                           (RetrieveClientCertificate);

        private readonly IHttpRouteData _routeData;
        private readonly HttpMessageInvoker _server;

        //构造函数中,默认制定了第一个HttpMessageHandler为HttpServer
        public HttpControllerHandler(RouteData routeData)
        : this(routeData, GlobalConfiguration.DefaultServer)
        {
        }

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

          _routeData = new HostedHttpRouteData(routeData);
          _server = new HttpMessageInvoker(handler);
        }

        public override Task ProcessRequestAsync(HttpContext context)
        {
          return ProcessRequestAsyncCore(new HttpContextWrapper(context));
        }

        internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase)
        {

          //创建HttpRequestMessage对象

          HttpRequestMessage request = contextBase.GetHttpRequestMessage() ?? ConvertRequest(contextBase);

          //把路由数据存放到HttpRequestMessage对象的属性字典中

          request.SetRouteData(_routeData);
          CancellationToken cancellationToken = contextBase.Response.GetClientDisconnectedTokenWhenFixed();
          HttpResponseMessage response = null;

          try
          {

            //调用方法将请求转出得到消息管道的第一个处理器,HttpServer(HttpMessageHandler)
            response = await _server.SendAsync(request, cancellationToken);
            await CopyResponseAsync(contextBase, request, response, _exceptionLogger.Value, _exceptionHandler.Value,
              cancellationToken);
          }
          catch (OperationCanceledException)
          {
            contextBase.Request.Abort();
          }
          finally
          {
            request.DisposeRequestResources();
            request.Dispose();

            if (response != null)
            {
              response.Dispose();
            }
          }
        }

      }

    二、路由注册

      我们新建一个Web应用程序的Web API项目时候,默认生成路由配置如下图:

      

      那怎么会寄宿到Web Host呢,而且还要用到前边介绍的这些类,来完成与ASP.NET 路由系统的集成,我们看到项目自动引用了程序集System.Web.Http.WebHost程序集,我们的Web Host模式的类都定义到这里,另外,根据前边介绍GlobalConfiguration默认使用了其中的类

      

      但是下边的代码明明是调用的是上一篇介绍的接口方法,config.Routes的类型是HttpRouteCollection,MapHttpRoute是其扩展方法,

      config.Routes.MapHttpRoute

      从前边知道,GlobalConfiguration指定的HostedHttpRouteCollection继承自HttpRouteCollection,对还是下边这句

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

      所以config.Routes实际类型是HostedHttpRouteCollection,再利用扩展方法的继承性,MapHttpRoute方法中调用的方法(其中调用了HttpRouteCollection的CreateRoute和Add方法),实际是HostedHttpRouteCollection中的方法。

      所以,我们实现了在Web Host模式下的路由注册。

    三、路由解析

      HostedHttpRouteCollection中的GetRouteData方法,其实际调用的是内部封装的ASP.NET路由的全局路由表(RouteCollection类型)的同名方法,请参考前边注释,或参考ASP.NET路由部分。

    四、生成URL

      HostedHttpRouteCollection中的GetVirtualPath方法,其实际调用的是内部封装的ASP.NET路由的全局路由表(RouteCollection类型)的同名方法,请参考前边注释,或参考ASP.NET路由部分。

    五、如何将请求转出到ASP.NET Web API 的核心消息处理管道

      从前边介绍可知道,我们默认指定了一个IRouteHandler为HttpControllerRouteHandler,其返回一个HttpControllerHandler类型的IHttpHandler,其封装了消息处理管道的第一个消息处理器HttpServer,在其ProcessRequestAsync方法中,会触发其执行,来启动ASP.NET Web API 消息处理管道。

  • 相关阅读:
    bzoj 1053
    bzoj 1004 组合
    字符串哈希
    bzoj 1015 并查集
    bzoj 1003 最短路+dp
    HDU 4352 数位dp
    bzoj 1879 状压dp
    codeforces 55D 数位dp
    Codeforces 830B
    组合计数 && Stirling数
  • 原文地址:https://www.cnblogs.com/shawnhu/p/8001130.html
Copyright © 2020-2023  润新知