zoukankan      html  css  js  c++  java
  • 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 消息处理管道。

  • 相关阅读:
    UVA 10617 Again Palindrome
    UVA 10154 Weights and Measures
    UVA 10201 Adventures in Moving Part IV
    UVA 10313 Pay the Price
    UVA 10271 Chopsticks
    Restore DB後設置指引 for maximo
    每行SQL語句加go換行
    种服务器角色所拥有的权限
    Framework X support IPV6?
    模擬DeadLock
  • 原文地址:https://www.cnblogs.com/shawnhu/p/8001130.html
Copyright © 2011-2022 走看看