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 消息处理管道。

ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道的更多相关文章

  1. ASP.NET Web API 框架研究 Self Host模式下的消息处理管道

    Self Host模式下的ASP.NET Web API与WCF非常相似,都可以寄宿在任意类型的托管应用程序中,宿主可以是Windows Form .WPF.控制台应用以及Windows Servic ...

  2. ASP.NET Web API 框架研究 Web Host模式下的消息处理管道

    寄宿的作用是开启一个进程为Web API提供一个运行环境以解决持续监听.请求监听和响应回复,即将接收到的请求转换成HttpRequestMessage对象传入管道,并将管道生成并经过处理后的HttpR ...

  3. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  4. ASP.NET Web API 框架研究 ASP.NET 路由

    ASP.NET Web API 如果采用Web Host方式来寄宿,在请求进入Web API 消息处理管道之前,就会用ASP.NET 自身的路由系统根据注册的路由表,解析出当前请求的HttpContr ...

  5. ASP.NET Web API 框架研究 Controller实例的销毁

    我们知道项目中创建的Controller,如ProductController都继承自ApiController抽象类,其又实现了接口IDisposable,所以,框架中自动调用Dispose方法来释 ...

  6. ASP.NET Web API 框架研究 核心的消息处理管道

    ASP.NET Web API 的核心框架是一个由一组HttpMessageHandler有序组成的双工消息处理管道:寄宿监听到请求接受后,把消息传入该管道经过所有HttpMessageHandler ...

  7. ASP.NET Web API 框架研究 Action方法介绍

    在根据请求解析出匹配的Controller类型并创建实例后,要在该Controller类型中的众多Action方法中选择与请求匹配的那一个,并执行,然后返回响应. Action方法,其元数据,主要包括 ...

  8. ASP.NET Web API 框架研究 服务容器 ServicesContainer

    ServicesContainer是一个服务的容器,可以理解为—个轻量级的IoC容器,其维护着一个服务接口类型与服务实例之间的映射关系,可以根据服务接口类型获取对应的服务实例.构成ASP.NET We ...

  9. ASP.NET Web API 框架研究 IoC容器 DependencyResolver

    一.概念 1.IoC(Inversion of Control),控制反转 即将依赖对象的创建和维护交给一个外部容器来负责,而不是应用本身.如,在类型A中需要使用类型B的实例,而B的实例的创建不是由A ...

随机推荐

  1. RoCE vs iWARP

    两种以太网 RDMA 协议: iWARP 和 RoCE 转载 2017年03月08日 16:10:09 1510 http://weibo.com/p/1001603936363903889917?m ...

  2. python之初接触

    编程语言相关 1什么是编程语言 编程语言即语言,语言的本质就是沟通,因而编程语言与英语 .法语.日语等所有语言并无区别,只不过英语是人与人之间沟通的介质,而编程语言则是程序员与计算机沟通的介质. 程序 ...

  3. Angular学习笔记:Angular CLI

    定义 Angular CLI:The Angular CLI is a command line interface tool that can create a project, add files ...

  4. regexper-正则表达式检验

    https://regexper.com 例如:输入 \s.?\w{1,3}(\d(\W)(#?\d{1..4}))

  5. 记录一次JVM调优【GC日志的分析】

    首先查看服务器版本默认信息: 修改tomcat/bin/catalina.sh,在最顶端加入JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -Xloggc ...

  6. Alpha 冲刺 (1/10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作,对多个目标检测及文字识别模型进行评估.实验,选取较 ...

  7. python学习 day3 (3月4日)---字符串

    字符串: 下标(索引) 切片[起始:终止] 步长[起始:终止:1] 或者-1 从后往前 -1 -2 -3 15个专属方法: 1-6  : 格式:大小写 , 居中(6) s.capitalize() s ...

  8. 在RedHat 和 Ubuntu 中配置 Delphi 的Linux开发环境(转)

    原文地址:http://chapmanworld.com/2016/12/29/configure-delphi-and-redhat-or-ubuntu-for-linux-development/ ...

  9. 前端之css操作2

    一 伪类选择器 伪类选择器就是在查找的后面加上冒号和状态 hover:悬浮到上面就会变化一种状态 link:没有接触的状态 active:点击是触发的状态 visited:点击后的状态 <!DO ...

  10. WPF中的依赖项属性(转)

    出处:https://www.cnblogs.com/axzxs2001/archive/2010/04/25/1719857.html 随着WPF的推广,不得不重新拾起WPF来,因为这块的产品越来越 ...