ASP.NET Web API 路由对象介绍

简介:

前言

在ASP.NET、ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了一些微小的修改,这也是根据每个框架的特性来制定的,今天我们就来看一看路由的结构,虽然我在MVC系列里写过路由的篇幅不过在这里是Web API 路由对象介绍。

 

ASP.NET Web API路由、管道

  • ASP.NET Web API 开篇介绍示例
  • ASP.NET Web API 路由对象介绍
  • ASP.NET Web API 管道模型
  • ASP.NET Web API selfhost宿主环境中管道、路由
  • ASP.NET Web API webhost宿主环境中管道、路由

 

路由系统概念

路由对象的结构

图1

路由系统中最重要的部分也就是路由对象了,那我们首先就来看一下【路由对象】的定义,不管是在ASP.NET、ASP.NET MVC、还是ASP.NET Web API的路由系统中路由都要有个名称,其实这个名称并不是路由对象中的而是在注册路由信息的时候,添加到路由对象集合的时候需要的名称,这里也只是当作路由的一部分,这个大家知道就好了。

在生成路由对象的时候我们要给路由赋值URL模板,这也是共同的,也是必须的,至于约束URL模板的条件是可以根据自己情况来定义的。在生成的同时框架会给路由对象赋值上【路由请求处理程序】用以作为衔接路由系统和框架的主体功能部分。

 

注册路由到系统框架中

图2

在路由定义好之后,我们便会把它注册到系统框架中。

 

路由对象的URL匹配

图3

在路由对象注册到系统框架中之后,这个时候如果有外部的请求的到达,这个时候路由系统会让路由对象集合中每个路由对象对这个请求进行匹配,就如图4一样。

图4

这个时候就是路由对象所要能做出的行为就是URL的匹配,根据什么来匹配?是根据在路由对象实例化的时候定义好的URL模板和条件,拿请求信息的URL和自身定义的URL模板进行匹配,假使没有匹配成功则会返回Null,这个时候框架则会让下一个路由对象来进行匹配直到有匹配的成功为止,如果这个时候匹配成功了路由则会生成一个【路由数据对象】。

 

路由数据对象也很重要,因为后续的框架功能部分都是使用它的,它也是整个路由系统的结晶,我们看下图5

图5

路由数据对象会保持一个生成它的路由对象的引用,然后是Values的是保存着路由对象在经过URL匹配后的值,分别表示着URL片段的名字和对应的URL真实值,而DataTokens则是在路由对象定义生成的时候直接带过来的值,当然了路由请求处理程序也是由执行生成的路由对象带来的。

 

在ASP.NET、ASP.NET MVC、ASP.NET Web API这些框架中路由系统都是遵循着上面的所述的这样一个过程,只不过在不同的框架环境下使用的类型不同,做的处理也不太一样,但是整体的流程是一致的,下面附上图6说明了之间的类型的差异性,还有更多的细节就不一一展示了。

图6

还有在Web API(WebHost)环境下路由显示的是这样实质的本质其实又是ASP.NET的路由系统在支持的,这个会在后面的Web API系列篇幅中讲解。

下面简单的演示一下在各种框架环境下的路由对象注册,

ASP.NET:

复制代码
复制代码
RouteTable.Routes.MapPageRoute(
                "ASP.NETRoute",
                "ProductInfo/{action}/{id}",
                "~/ProductInfo.aspx",
                true,
                new RouteValueDictionary { { "id", RouteParameter.Optional }, { "action", "show" } }
                );
复制代码
复制代码

 

ASP.NET MVC:

            RouteTable.Routes.MapRoute(
                "ASP.NETMVCRoute",
                "ProductInfo/{action}/{id}",
                new { controller="Product",action="show",id=RouteParameter.Optional}
                );

ASP.NET Web API(WEBHOST):

            GlobalConfiguration.Configuration.Routes.MapHttpRoute(
               "WebAPIRoute",
               "api/{controller}/{id}", new { id = RouteParameter.Optional }
               );

ASP.NET Web API(SELFHOST):

复制代码
复制代码
HttpSelfHostConfiguration configuration = 
                new HttpSelfHostConfiguration("http://loacalhost/selfhost");
            using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer(configuration))
            {
                selfHostServer.Configuration.Routes.MapHttpRoute(
                    "DefaultApi", "api/{controller}/{id}", new { id=RouteParameter.Optional});
               
                selfHostServer.OpenAsync();
                Console.Read();
            }
复制代码
复制代码

 

 

ASP.NET Web API 路由系列对象

从上图的图表中就可以看出,ASP.NET Web API框架在不同的宿主环境下路由系统中所对应的对象类型是不同的,这里就先给大家介绍在SelfHost环境下的路由系统中的路由对象吧。

 

SelfHost宿主环境

 

Web API路由对象(System.Web.Http.Routing)

HttpRoute

复制代码
复制代码
    // 摘要:
    //     表示自承载(即在 ASP.NET 之外承载)的路由类。
    public class HttpRoute : IHttpRoute
    {
        public HttpRoute(string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens, HttpMessageHandler handler);

        public IDictionary<string, object> Constraints { get; }
        public IDictionary<string, object> DataTokens { get; }
        public IDictionary<string, object> Defaults { get; }
        public HttpMessageHandler Handler { get; }
        public string RouteTemplate { get; }
        public virtual IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request);
        public virtual IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);
        protected virtual bool ProcessConstraint(HttpRequestMessage request, object constraint, string parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection);
    }
复制代码
复制代码

可以从上面的定义中看到HttpRoute对象就是代表着在Web API框架中的路由对象了,在HttpRoute类型定义的构造函数中的参数分别表示着路由模板、路由模板对应的默认值、路由匹配条件、注册的路由附带的值以及最后的Http请求处理程序,这几个参数值也分别对应着HttpRoute类型中的几个属性,这个自行看一下就明白了。

 

Web API路由对象集合(System.Web.Http)

HttpRouteCollection

HttpRouteCollectionExtensions

 

我们先来看一下HttpRouteCollection类型的扩展类型HttpRouteCollectionExtensions吧

复制代码
复制代码
    public static class HttpRouteCollectionExtensions
    {
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate);
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults);
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints);
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler);
    }
复制代码
复制代码

这里大家可以对比上面的路由注册时的代码,就可以知道我们在路由集合 添加/注册 路由的时候是由HttpRouteCollectionExtensions类型的扩展方法来进行操作的,这个时候我们再看一下方法参数最多的那个MapHttpRoute()方法的实现:

复制代码
复制代码
public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
        {
            if (routes == null)
            {
                throw System.Web.Http.Error.ArgumentNull("routes");
            }
            HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults);
            HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints);
            IDictionary<string, object> dataTokens = null;
            HttpMessageHandler handler2 = handler;
            IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);
            routes.Add(name, route);
            return route;
        }
复制代码
复制代码

这里大家就可以看到了,HttpRoute对象的创建操作和添加操作是在这扩展方法里执行的,现在我们就可以去看一下HttpRouteCollection类型的定义了,看一下如何创建的IHttpRoute对象:

复制代码
复制代码
    public class HttpRouteCollection : ICollection<IHttpRoute>, IEnumerable<IHttpRoute>, IEnumerable, IDisposable
    {
        public HttpRouteCollection();
        public HttpRouteCollection(string virtualPathRoot);

        public virtual int Count { get; }
        public virtual bool IsReadOnly { get; }
        public virtual string VirtualPathRoot { get; }

        public virtual void Add(string name, IHttpRoute route);
        public IHttpRoute CreateRoute(string routeTemplate, object defaults, object constraints);
        public IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens);
        public virtual IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);
        public virtual IHttpRouteData GetRouteData(HttpRequestMessage request);
    }
复制代码
复制代码

这里只是其中的一部分,下面我们就来看一下具体的实现,其实就是实例化一个HttpRoute路由对象根据用户配置的参数信息:

复制代码
复制代码
public virtual IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
        {
            HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults);
            HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints);
            return new HttpRoute(routeTemplate, dictionary, dictionary2, new HttpRouteValueDictionary(dataTokens), handler);
        }
复制代码
复制代码

这是路由对象集合类型的第一个作用就是添加/注册 路由信息,那么第二个呢?就是根据请求信息来匹配路由对象,上面也说过了,其实真正根据请求来匹配的并不是路由对象集合类型(HttpRouteCollection),而是在其中的每个路由,我们看一下HttpRouteCollection的障眼法:

复制代码
复制代码
public virtual IHttpRouteData GetRouteData(HttpRequestMessage request)
        {
            if (request == null)
            {
                throw System.Web.Http.Error.ArgumentNull("request");
            }
            foreach (IHttpRoute route in this._collection)
            {
                IHttpRouteData routeData = route.GetRouteData(this._virtualPathRoot, request);
                if (routeData != null)
                {
                    return routeData;
                }
            }
            return null;
        }
复制代码
复制代码

从这里可以看出在路由匹配完成后会返回一个实现IHttpRouteDatarouteData接口的对象,也就是上面所说的路由数据对象。

 

Web API路由数据对象(System.Web.Http.Routing)

HttpRouteData

复制代码
复制代码
    public class HttpRouteData : IHttpRouteData
    {
        public HttpRouteData(IHttpRoute route);
        public HttpRouteData(IHttpRoute route, HttpRouteValueDictionary values);

        public IHttpRoute Route { get; }
        public IDictionary<string, object> Values { get; }
    }
复制代码
复制代码

 

其实这里都不用讲了,上面都讲过了,HttpRouteData对象包含着生成它的路由对象(HttpRoute)的引用,并且Values值就是经过匹配过后的路由模板值,key键对应着Url模板的片段值,value对应着的是片段对应的真实值。

 

SelfHost环境下的路由就说到这里,大家看一下如下的示意图,简单的表示了在SelfHost环境下路由的一个处理过程,具体的细节会在后面的篇幅讲解。

图7

 

WebHost宿主环境

 

Web API路由对象(System.Web.Http.WebHost.Routing)

HostedHttpRoute

复制代码
复制代码
    internal class HostedHttpRoute : IHttpRoute
    {
        // Methods
        public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);
        public IHttpRouteData GetRouteData(string rootVirtualPath, HttpRequestMessage request);
        public IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);

        // Properties
        public IDictionary<string, object> Constraints { get; }
        public IDictionary<string, object> DataTokens { get; }
        public IDictionary<string, object> Defaults { get; }
        public HttpMessageHandler Handler { get; private set; }
        internal Route OriginalRoute { get; private set; }
        public string RouteTemplate { get; }
}
复制代码
复制代码

从上面的代码定义中可以看到HostedHttpRoute是程序集内部类型,并且是直接继承自IHttpRoute接口,跟SelfHost环境中的HttpRoute对象是一点关系都没有。

从它定义的内部结构来看它跟HttpRoute对象的结构相似,还是那些属性那些个对象,唯一不同的就是多了个OriginalRoute的只读属性(对于外部来说),这个属性也就是封装的HttpWebRoute对象,看下封装时的实现

复制代码
复制代码
public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
    {
        RouteValueDictionary dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null;
        RouteValueDictionary dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null;
        RouteValueDictionary dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null;
        this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this);
        this.Handler = handler;
    }
复制代码
复制代码

在HostedHttpRoute对象构造函数中可以清楚的看到OriginalRoute属性是赋值的HttpWebRoute对象的实例,我们现在就来看一下HttpWebRoute对象的定义

复制代码
复制代码
    internal class HttpWebRoute : Route
    {
        // Fields
        internal const string HttpRouteKey = "httproute";

        // Methods
        public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler, IHttpRoute httpRoute);
        private static HttpRouteDirection ConvertRouteDirection(RouteDirection routeDirection);
        private static RouteValueDictionary GetRouteDictionaryWithoutHttpRouteKey(IDictionary<string, object> routeValues);
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
        protected override bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);

        // Properties
        public IHttpRoute HttpRoute { get; private set; }
}
复制代码
复制代码

 

从这里可以看到HttpWebRoute对象继承自ASP.NET中的Route对象,现在就可以理解为HostedHttpRoute对象持有对ASP.NET中Route对象的引用,而在HostedHttpRoute的构造函数实现中,对OriginalRoute属性是赋值实例化的时候,在最后传入了一个HttpControllerRouteHandler类型的路由处理程序,实则是给ASP.NET中的Route对象的路由处理程序(Routehandler属性)进行的赋值。这里路由的具体的操作后续篇幅中会有讲到一个全面的过程。

 

Web API路由对象集合(System.Web.Http.WebHost.Routing

HostedHttpRouteCollection

 

复制代码
复制代码
internal class HostedHttpRouteCollection : HttpRouteCollection
        {
            // Fields
            private readonly RouteCollection _routeCollection;

            // Methods
            public HostedHttpRouteCollection(RouteCollection routeCollection);
            public override void Add(string name, IHttpRoute route);
            public override void Clear();
            public override bool Contains(IHttpRoute item);
            public override bool ContainsKey(string name);
            public override void CopyTo(IHttpRoute[] array, int arrayIndex);
            public override void CopyTo(KeyValuePair<string, IHttpRoute>[] array, int arrayIndex);
            public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);
            public override IEnumerator<IHttpRoute> GetEnumerator();
            public override IHttpRouteData GetRouteData(HttpRequestMessage request);
            public override IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, string name, IDictionary<string, object> values);
            public override void Insert(int index, string name, IHttpRoute value);
            private static NotSupportedException NotSupportedByHostedRouteCollection();
            private static NotSupportedException NotSupportedByRouteCollection();
            public override bool Remove(string name);
            public override bool TryGetValue(string name, out IHttpRoute route);

            // Properties
            public override int Count { get; }
            public override IHttpRoute this[string name] { get; }
            public override IHttpRoute this[int index] { get; }
            public override string VirtualPathRoot { get; }
        }
复制代码
复制代码

看到这里的代码定义,HostedHttpRouteCollection对象同样也是程序集内部类型,继承自ASP.NET中的RouteCollection对象,这里要说是CreateRoute()方法和GetRouteData()方法返回的分别是HostedHttpRoute对象和HostedHttpRouteData对象,其实在GetRouteData()方法中起初生成的就是Routedata对象,只不过在返回的时候经过HostedHttpRouteData对象封装了一下。

 

Web API路由数据对象(System.Web.Http.WebHost.Routing)

HostedHttpRouteData

这里我们看一下HostedHttpRouteData类型的定义:

复制代码
复制代码
        internal class HostedHttpRouteData : IHttpRouteData
        {
            // Methods
            public HostedHttpRouteData(RouteData routeData);

            // Properties
            internal RouteData OriginalRouteData { get; private set; }
            public IHttpRoute Route { get; private set; }
            public IDictionary<string, object> Values { get; }
        }
复制代码
复制代码

从构造函数的定义就可以看出来是HostedHttpRouteData是封装的RouteData对象,这些路由流程细节后面篇幅中会有讲解。

 

最后我们看一下在WebHost宿主环境下的路由示意图。

图8

 

分类:  Web API

本文转自左正博客园博客,原文链接:http://www.cnblogs.com/soundcode/p/4051782.html ,如需转载请自行联系原作者
相关文章
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
61 4
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
170 3
|
19天前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
44 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
1月前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
|
1月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
54 1
|
1月前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
125 2
|
2月前
|
监控 负载均衡 API
Web、RESTful API 在微服务中有哪些作用?
在微服务架构中,Web 和 RESTful API 扮演着至关重要的角色。它们帮助实现服务之间的通信、数据交换和系统的可扩展性。
61 2
|
2月前
|
人工智能 搜索推荐 API
用于企业AI搜索的Bocha Web Search API,给LLM提供联网搜索能力和长文本上下文
博查Web Search API是由博查提供的企业级互联网网页搜索API接口,允许开发者通过编程访问博查搜索引擎的搜索结果和相关信息,实现在应用程序或网站中集成搜索功能。该API支持近亿级网页内容搜索,适用于各类AI应用、RAG应用和AI Agent智能体的开发,解决数据安全、价格高昂和内容合规等问题。通过注册博查开发者账户、获取API KEY并调用API,开发者可以轻松集成搜索功能。
|
2月前
|
前端开发 JavaScript API
惊呆了!学会AJAX与Fetch API,你的Python Web项目瞬间高大上!
在Web开发领域,AJAX与Fetch API是提升交互体验的关键技术。AJAX(Asynchronous JavaScript and XML)作为异步通信的先驱,通过XMLHttpRequest对象实现了局部页面更新,提升了应用流畅度。Fetch API则以更现代、简洁的方式处理HTTP请求,基于Promises提供了丰富的功能。当与Python Web框架(如Django、Flask)结合时,这两者能显著增强应用的响应速度和用户体验,使项目更加高效、高大上。
56 2
|
2月前
|
前端开发 API 开发者
从零到精通,AJAX与Fetch API让你的Python Web前后端交互无所不能!
从零到精通,AJAX与Fetch API让你的Python Web前后端交互无所不能!
49 3