Asp.Net WebAPI核心对象解析(三)

 百万发平台     |      2020-01-01 03:03

   对于.NET的分布式应用开发,可以供我们选择的技术和框架比较多,例如webservice,.net remoting,MSMQ,WCF等等技术。对于这些技术很多人都不会陌生,即时没有深入的了解,但是肯定听说过,每种技术都各有优势和适用范围,没有绝对的好坏,只有相对的合适程度。不过可惜了,今天我们讲解的主题不是这几种技术,今天主要讲解的是ASP.NET WebAPI。

由于工作的原因,断断续续终于看完了《ASP.NET Web API 2 框架揭秘》第二章关于WebApi的路由系统的知识。

   对于ASP.NET WebAPI的优势和特点,在这里就不讲了,需要用到的自然就会选择,也不需要我浪费篇幅去讲解这些,这篇博文主要讲解ASP.NET WebAPI中的HTTP消息的结构和处理消息的核心对象。

路由系统是请求消息进入Asp.net WebApi的第一道屏障,其根本目的利用注册的路由表对请求的URI进行解析以确定目标HttpController和Action的名称,以及与某个Action方法某个参数进行绑定的路由变量。

一.WebAPI的HTTP概述:

   有关HTTP协议的相关内容在这里就不做介绍,在笔者前面的博文中已经做过介绍,现在提供一下地址,因为过多的赘述就是浪费时间,我就姑且看这篇博文的读者已经对HTTP协议和WebAPI都有所了解。博文地址:

Asp.net webApi中的路由系统和Asp.net中的路由系统很相似,也有Route,只是WebApi的路由系统又独立于Asp.net的路由系统,实现类也在不同的命名空间下。所以在讲Asp.net WebApi路由之前先来谈谈Asp.net路由系统。

   1.在.NET4.5之前的版本中,处理HTTP的核心对象:

      (1).在客户端:System.Net.HttpWebRequest用于初始化HTTP请求,处理相关的响应; System.Net.HttpWebResponse处理HTTP响应头和数据读取的检索。

      (2).在服务器端:System.Web.HttpContext,System.Web.HttpRequest,System.Web.HttpResponse类用在ASP.NET上下文中,代表单个请求和响应。System.Net.HttpListenerContext类,提供对HTTP请求和响应对象的访问。

一、Asp.net 路由

   2.在.NET4.5版本中,处理HTTP的核心对象:

      (1).在客户端和服务器端使用同样的类。(HttpRequestMessage和HttpResponseMessage对象中不包含上下文消息,所以可以在服务器和客户端共用。)

      (2).由于在.NET4.5中引入了TAP(异步任务模型),所以在新的HTTP模型中,处理HTTP请求的方法可以使用async和awit实现异步编程。(可以简单高效的实现异步编程)

    我们对于新旧的HTTP编程模型时,会很容易的发现在新版本的HTTP模型中,无论是编程的难度和代码编写的精简度,已经执行的效率都是很高的。在对于Web项目的开发中,我们对HTTP知识的了解是必要的,对于ASP.NET的HTTP处理的原理在这里就不做具体的介绍,网上也有比较多的文章可供阅读和了解。

    对于ASP.NET的HTTP处理方式的了解,是我在开发微信公众平台时进一步学习的,微信公众平台提供了对外访问的接口,我们的程序和服务器对微信服务器的接口进行请求访问,微信服务器获取HTTP请求后,返回处理结果,本地服务器获取返回结果。这样一个请求-响应模式,组成一个会话。对于微信公众平台的开发对于很多刚学习.NET的人来说有些高大(当然这是相对而言),即时开发过很多次这个类别的程序的人(调用第三方接口的开发)也不一定可以很清晰的知道这个其中的原理,笔者觉得对于这样的第三方平台的开发,其主要的核心部分就是对于HTTP协议的处理,建立请求、获取响应消息和解析消息这三大步骤,返回的消息内容一般为json或者xml,获取响应消息后,主要是对消息内容的反序列化,获得消息的实体信息,进而在程序中进一步处理。

    在WeAPI中消息的产生和解析,以及消息的格式都是可以动态的创建和协商,下面我们进一步的了解实现这一过程的核心对象。

Asp.net MVC的路由完全由 Asp.net路由系统来完成 ,但是后者并非专门为前者设计 ,其实它最初是为了帮助 WebForm应用实现 “请求地址与物理文件的分离” 而设计的。

二.WebAPI的HTTP消息解析:

      HTTP协议的工作方式是在客户端和服务器之间交换请求和响应消息,那么这也就可以说明HTTP的核心就是消息,对于“消息”的了解,我们只要知道消息分为“消息头部”和“消息内容”,我们接下来的对新HTTP编程模型的介绍的主体就是“消息头部”和“消息内容”。

      在命名空间System.Net.Http中,具有两个核心对象:HttpRequestMessage和HttpResponseMessage。两个对象的结构如下图:

图片 1

      以上主要讲解了HttpRequestMessage对象和HttpResponseMessage对象包含的主要内容,请求和响应消息都可以包含一个可选的消息正文,两中消息类型以及消息内容,都可以使用响应的标头。接下来具体了解一些消息的结构。

 

    1.HttpRequestMessage对象解析:

         (1).HttpRequestMessage主要属性和方法概述:

名称 说明
Version 获取或设置 HTTP 消息版本
Content 获取或设置 HTTP 消息的内容
Method 获取或设置 HTTP 请求信息使用的 HTTP 方法
RequestUri 获取或设置 HTTP 请求的 Uri
Headers 获取 HTTP 请求标头的集合
Properties 获取 HTTP 请求的属性集
ToString 返回表示当前对象的字符串

        该对象主要用于表示 HTTP 请求消息。对于该对象的这些属性和方法,大部分应该都不会陌生,因为一个HTTP消息中主要包含头部、消息内容等等,在这里主要介绍一个属性Properties,该属性并不属于任何标准的HTTP消息,当消息传输时,不会保留该属性。

         (2).Properties属性解析:

[__DynamicallyInvokable]
public IDictionary<string, object> Properties
{
    [__DynamicallyInvokable]
    get
    {
        if (this.properties == null)
        {
            this.properties = new Dictionary<string, object>();
        }
        return this.properties;
    }
}

    有以上的代码可以很明显的看出该属性只有一个只读属性,并返回一个IDictionary<string, object>。当消息在服务器或者客户端本地进行处理时,该属性用于保存附加的消息信息。该属性只是一个通用的容器,保存本地消息属性。(与接受消息的连接相关的客户端认证;将消息与配置路由进行匹配,得到的路由数据)

1.1 请求Url与物理文件的分离:类似于www.xxx.com/default.aspx这类没有把url与物理地址分开的做法的局限性体现在一下几个方面,1.灵活性(物理文件路径发生变化,链接无效);2.可读性;3.SEO优化。

   2.HttpResponseMessage对象解析:

        (1).HttpRequestMessage主要属性和方法概述:

名称 说明
EnsureSuccessStatusCode 如果 HTTP 响应的 IsSuccessStatusCode 属性为  false, 将引发异常
StatusCode 获取或设置 HTTP 响应的状态代码
ReasonPhrase 获取或设置服务器与状态代码通常一起发送的原因短语
RequestMessage 获取或设置导致此响应消息的请求消息
IsSuccessStatusCode 获取一个值,该值指示 HTTP 响应是否成功

      对于该对象的一些属性没有列举,因为在HttpRequestMessage对象已经介绍,如:Version、Content、Headers等,该对象主要用于表示 HTTP 响应消息。在这里主要介绍StatusCode属性。

       (2).StatusCode属性:

[__DynamicallyInvokable]
public HttpStatusCode StatusCode
{
    [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    get
    {
        return this.statusCode;
    }
    [__DynamicallyInvokable]
    set
    {
        if ((value < ((HttpStatusCode) 0)) || (value > ((HttpStatusCode) 0x3e7)))
        {
            throw new ArgumentOutOfRangeException("value");
        }
        this.CheckDisposed();
        this.statusCode = value;
    }
}

     StatusCode属性为枚举属性,该属性可读可写,对于状态码这个概念,很多人都是比较了解的,在HTTP协议中,状态码主要是表示在消息的请求在服务器中处理的结果,状态有2XX,3XX,4XX,5XX等等,具体表示的意义就不再描述。

解决上面问题,URL路由系统,通过托管代码实现URL与物理文件的分离。

     3.HTTP模型消息标头解析:

          在HTTP中,请求和响应消息,以及消息内容自身,都可以使用称为标头的额外字段,包含更多的信息。

       (1).标头分类:

标头名称 描述 HTTP模型标头容器类
User-Agent 为请求提供扩展信息,描述产生这个请求的应用程序 HttpRequestHeaders
Server 为响应提供关于源服务器软件的扩展信息 HttpResponseHeaders
Content-Type 定义请求或响应有效载荷正文中,资源表示使用的媒体类型 HttpContentHeaders

       (2).HttpHeaders抽象类分析:

名称 描述
Add 添加指定的标头及其值到 HttpHeaders 集合中。
TryAddWithoutValidation 返回一个值,该值指示指定标头及其值是否已添加到HttpHeaders 集合,而未验证所提供的信息。
Clear 从 HttpHeaders 集合中移除所有标头。
Remove 从HttpHeaders集合中移除指定的标头。
GetValues 返回存储在HttpHeaders 集合中所有指定标头的标头值。
Contains 如果指定标头存在于 HttpHeaders 集合则返回。
ToString 返回表示当前 HttpHeaders对象的字符串。

       HttpHeaders是一个抽象类,HttpRequestHeaders、HttpResponseHeaders、HttpContentHeaders三个类继承了该类。接下来我们来了解一下Add()方法:

[__DynamicallyInvokable]
public void Add(string name, string value)
{
    HeaderStoreItemInfo info;
    bool flag;
    this.CheckHeaderName(name);
    this.PrepareHeaderInfoForAdd(name, out info, out flag);
    this.ParseAndAddValue(name, info, value);
    if (flag && (info.ParsedValue != null))
    {
        this.AddHeaderToStore(name, info);
    }
}

       Add()方法具有两个重载版本,该方法可以向容器添加标头,如果要添加的标头有标准名,在添加之前标头值会进行验证。Add方法还会验证标头是否可以有多个值。

下面示例展示了通过URL路由实现请求地址与web页面的映射。示例地址:员工列表与员工信息示例

   4.HTTP消息内容解析:

      在.NET4.5版本的HTTP模型中,HTTP消息的正文由抽象基类HttpContent表示,HttpResponseMessage和HttpRequestMessage对象都包含一个HttpContent类型的Content属性。

     (1).HttpContent主要属性和方法:

名称 描述
ReadAsByteArrayAsync 以异步操作将 HTTP 内容写入字节数组。
SerializeToStreamAsync 以异步操作将 HTTP 内容序列化到流。
CopyToAsync 以异步操作将 HTTP 内容写入流。
LoadIntoBufferAsync 以异步操作将 HTTP 内容序列化到内存缓冲区。
CreateContentReadStreamAsync 以异步操作将 HTTP 内容写入内存流。
TryComputeLength 确定 HTTP 内容是否具备有效的字节长度。
Headers 根据 RFC 2616 中的定义,获取内容标头。

     (2).CopyToAsync()方法解析:

[__DynamicallyInvokable]
public Task CopyToAsync(Stream stream, TransportContext context)
{
    Action<Task> continuation = null;
    this.CheckDisposed();
    if (stream == null)
    {
        throw new ArgumentNullException("stream");
    }
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    try
    {
        Task task = null;
        if (this.IsBuffered)
        {
            task = Task.Factory.FromAsync<byte[], int, int>(new Func<byte[], int, int, 
            AsyncCallback, object, IAsyncResult>(stream.BeginWrite), new Action<IAsyncResult>(stream.EndWrite), 
       this.bufferedContent.GetBuffer(), 0, (int) this.bufferedContent.Length, null);
        }
        else
        {
            task = this.SerializeToStreamAsync(stream, context);
            this.CheckTaskNotNull(task);
        }
        if (continuation == null)
        {
            continuation = delegate (Task copyTask) {
                if (copyTask.IsFaulted)
                {
                    tcs.TrySetException(GetStreamCopyException(copyTask.Exception.GetBaseException()));
                }
                else if (copyTask.IsCanceled)
                {
                    tcs.TrySetCanceled();
                }
                else
                {
                    tcs.TrySetResult(null);
                }
            };
        }
        task.ContinueWithStandard(continuation);
    }
    catch (IOException exception)
    {
        tcs.TrySetException(GetStreamCopyException(exception));
    }
    catch (ObjectDisposedException exception2)
    {
        tcs.TrySetException(GetStreamCopyException(exception2));
    }
    return tcs.Task;
}

    在使用消息内容时,需要使用HtppContent的方法或者扩展方法。在HttpContent中利用CopyToAsync()方法以推送方式访问原始的消息内容,由方法代码可以看出,该方法接受两个参数,一个是流对象,一个是有关传输的信息(例如,通道绑定),此参数可以为 null。该方法可以把消息内容写入到这个流中。

    在该方法的实现代码中 创建了一个TaskCompletionSource<object>的泛型对象,该对象表示未绑定到委托的 Task<TResult> 的制造者方,并通过 Task 属性提供对使用者方的访问。SerializeToStreamAsync方法将传入的流对象序列化,该方法为异步方法。

    我们需要注意的几点,主要为委托的创建和使用,在C#中,尽量使用有.NET提供的委托类,不要自己去创建。还有一点就是在程序中对异常的处理方式,异常的捕获具有层次性,并且调用了自定义的一个异常处理方法TrySetException。

    (2).ReadAsStreamAsync()方法解析:

Asp.Net WebAPI核心对象解析(三)。      在获取原始消息内容时,除了调用上面介绍的方法外,还可以调用ReadAsStreamAsync()方法以拉取的方式访问原始的消息内容。

      在HttpContent中包含有另外两个类似的方法,ReadAsStringAsync()和ReadAsByteArrayAsync()异步的提供消息内容的缓冲副本,ReadAsByteArrayAsync()返回原始的字节内容,ReadAsStringAsync()将内容解码为字符串返回。

图片 2图片 3

三.DotNet中新旧HTTP模型分析:

 1 namespace WebApp
 2 {
 3     public class Global : System.Web.HttpApplication
 4     {
 5         protected void Application_Start(object sender, EventArgs e)
 6         {
 7             var defaults = new RouteValueDictionary { { "name", "*" }, { "id", "*" } };
 8             RouteTable.Routes.MapPageRoute("", "employees/{name}/{id}","~/default.aspx", true, defaults);
 9         }
10     }
11 }
12       

   1..NET4.5之前版本创建HTTP POST请求实例:

        public static string HttpPost(string postUrl, string postData)
        {
            if (string.IsNullOrEmpty(postUrl))
                throw new ArgumentNullException(postUrl);
            if (string.IsNullOrEmpty(postData))
                throw new ArgumentNullException(postData);
            var request = WebRequest.Create(postUrl) as HttpWebRequest;
            if (request == null)
                throw new ArgumentNullException("postUrl");
            try
            {
                var cookieContainer = new CookieContainer();
                request.CookieContainer = cookieContainer;
                request.AllowAutoRedirect = true;
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                var data = Encoding.UTF8.GetBytes(postData);
                request.ContentLength = data.Length;
                var outstream = request.GetRequestStream();
                outstream.Write(data, 0, data.Length);
                outstream.Close();
                //发送请求并获取相应回应数据,获取对应HTTP请求的响应
                var response = request.GetResponse() as HttpWebResponse;
                if (response != null)
                {
                    var instream = response.GetResponseStream();
                    var content = string.Empty;
                    if (instream == null)
                    {
                        return content;
                    }
                    using (var sr = new StreamReader(instream, Encoding.UTF8))
                    {
                        content = sr.ReadToEnd();
                    }
                    return content;
                }
            }
            catch (ArgumentException arex)
            {
                throw arex;
            }
            catch (IOException ioex)
            {
                throw ioex;
            }
            return null;
        }

Global

   2..NET4.5版本创建HTTP POST请求实例:

async static void getResponse(string url)
        {
            using (HttpClient client = new HttpClient())
            {
                using (HttpResponseMessage response = await client.GetAsync(url))
                {
                    using (HttpContent content = response.Content)
                    {
                        string myContent = await content.ReadAsStringAsync();
                    }
                }
            }
        }
        async static void postResponse(string url)
        {
            while (true)
            {
                IEnumerable<KeyValuePair<string, string>> queries = new List<KeyValuePair<string, string>>()
            {
                new KeyValuePair<string, string> ("test","test")
            };
                HttpContent q = new FormUrlEncodedContent(queries);
                using (HttpClient client = new HttpClient())
                {
                    using (HttpResponseMessage response = await client.PostAsync(url, q))
                    {
                        using (HttpContent content = response.Content)
                        {
                            string myContent = await content.ReadAsStringAsync();

                            Console.WriteLine(myContent);
                        }
                    }
                }
            }
        }

在示例中有我们将实现映射的路由注册代码定义在 Global.asax文件中,调用system.Web.Routing.RouteCollection对象的MapPageRoute方法将Default.aspx页面 (~/Default.aspx)与一个路由模板(employees/{name}/{id})进行了映射.

四.总结:

   以上主要讲解了.NET4.5之前和之后版本对HTTP编程模式的一些内容, 两者的主要区别在于.NET4.5版本之前的HTTP编程模型会区分客户端和服务器,两者使用的对象存在不同,实现的原理上虽然存在一定的相似性,但是使用的类却不同。.NET4.5之后的版本中,对象的使用没有客户端和服务器之分,两者可以共用。

MapPageRoute的最后一个参数RouteValueDictionary用于指定在路由模版中路由变量(“name”和“id”)的默认值。对于针对URL为 “/employees” 的请求,我们注册的 Route会将其格式化成 “/employees/*/*".

 

1.2 ASP.Net 路由系统(重要类分析):

1.RouteBase

  命名空间:  System.Web.Routing

      属性:RouteExistingFiles 

      方法:GetRouteData、GetVirtualPath、RouteBase

图片 4图片 5

 1  // 摘要: 
 2     //     用作表示 ASP.NET 路由的所有类的基类。
 3     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
 4     public abstract class RouteBase
 5     {
 6         // 摘要: 
 7         //     初始化该类供继承的类实例使用。 此构造函数只能由继承的类调用。
 8         protected RouteBase();
 9 
10         // 摘要: 
11         //     获取或设置一个值,该值指示 ASP.NET 路由操作是否应处理与现有文件匹配的 URL。
12         //
13         // 返回结果: 
14         //     如果 ASP.NET 路由操作处理所有请求(甚至包括与现有文件匹配的请求),则为 true;否则为 false。 默认值为 false。
15         public bool RouteExistingFiles { get; set; }
16 
17         // 摘要: 
18         //     当在派生类中重写时,会返回有关请求的路由信息。
19         //
20         // 参数: 
21         //   httpContext:
22         //     一个对象,封装有关 HTTP 请求的信息。
23         //
24         // 返回结果: 
25         //     一个对象,包含路由定义的值(如果该路由与当前请求匹配)或 null(如果该路由与请求不匹配)。
26         public abstract RouteData GetRouteData(HttpContextBase httpContext);
27         //
28         // 摘要: 
29         //     当在派生类中重写时,会检查路由是否与指定值匹配,如果匹配,则生成一个 URL,然后检索有关该路由的信息。
30         //
31         // 参数: 
32         //   requestContext:
33         //     一个对象,封装有关所请求的路由的信息。
34         //
35         //   values:
36         //     一个包含路由参数的对象。
37         //
38         // 返回结果: 
39         //     一个对象(包含生成的 URL 和有关路由的信息)或 null(如果路由与 values 不匹配)。
40         public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
41     }

RouteBase

2.RouteData

      命名空间:  System.Web.Routing

      属性:Route、DataTokens(说明:直接附加到Route上的自定义变量)、RouteHandler 、Values(说明:Route通过对请求的Url的解析得到的) 

      方法:两个构造函数RouteData、GetRequiredString

图片 6图片 7

 1  // 摘要: 
 2     //     封装有关路由的信息。
 3     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
 4     public class RouteData
 5     {
 6         // 摘要: 
 7         //     初始化 System.Web.Routing.RouteData 类的新实例。
 8         public RouteData();
 9         //
10         // 摘要: 
11         //     使用指定路由和路由处理程序初始化 System.Web.Routing.RouteData 类的新实例。
12         //
13         // 参数: 
14         //   route:
15         //     一个定义路由的对象。
16         //
17         //   routeHandler:
18         //     一个处理请求的对象。
19         public RouteData(RouteBase route, IRouteHandler routeHandler);
20 
21         // 摘要: 
22         //     获取在 ASP.NET 路由确定路由是否匹配请求时,传递到路由处理程序但未使用的自定义值的集合。
23         //
24         // 返回结果: 
25         //     一个包含自定义值的对象。
26         public RouteValueDictionary DataTokens { get; }
27         //
28         // 摘要: 
29         //     获取或设置表示路由的对象。
30         //
31         // 返回结果: 
32         //     一个表示路由定义的对象。
33         public RouteBase Route { get; set; }
34         //
35         // 摘要: 
36         //     获取或设置处理所请求路由的对象。
37         //
38         // 返回结果: 
39         //     一个处理路由请求的对象。
40         public IRouteHandler RouteHandler { get; set; }
41         //
42         // 摘要: 
43         //     获取路由的 URL 参数值和默认值的集合。
44         //
45         // 返回结果: 
46         //     一个对象,其中包含根据 URL 和默认值分析得出的值。
47         public RouteValueDictionary Values { get; }
48 
49         // 摘要: 
50         //     使用指定标识符检索值。
51         //
52         // 参数: 
53         //   valueName:
54         //     要检索的值的键。
55         //
56         // 返回结果: 
57         //     其键与 valueName 匹配的 System.Web.Routing.RouteData.Values 属性中的元素。
58         //
59         // 异常: 
60         //   System.InvalidOperationException:
61         //     valueName 的值不存在。
62         public string GetRequiredString(string valueName);
63     }

RouteData

 3.VirtualPathData

  命名空间:  System.Web.Routing

      属性:VirtualPath、Route、DataTokens 

      方法:构造函数VirtualPathData

图片 8图片 9

 1     // 摘要: 
 2     //     表示有关路由和虚拟路径的信息,该路由和虚拟路径是在使用 ASP.NET 路由框架生成 URL 时产生的。
 3     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
 4     public class VirtualPathData
 5     {
 6         // 摘要: 
 7         //     初始化 System.Web.Routing.VirtualPathData 类的新实例。
 8         //
 9         // 参数: 
10         //   route:
11         //     用于生成 URL 的对象。
12         //
13         //   virtualPath:
14         //     生成的 URL。
15         public VirtualPathData(RouteBase route, string virtualPath);
16 
17         // 摘要: 
18         //     获取路由定义的自定义值集合。
19         //
20         // 返回结果: 
21         //     路由的自定义值集合。
22         public RouteValueDictionary DataTokens { get; }
23         //
24         // 摘要: 
25         //     获取或设置用于创建 URL 的路由。
26         //
27         // 返回结果: 
28         //     一个对象,该对象表示与用于生成 URL 的参数匹配的路由。
29         public RouteBase Route { get; set; }
30         //
31         // 摘要: 
32         //     获取或设置依据路由定义创建的 URL。
33         //
34         // 返回结果: 
35         //     依据路由生成的 URL。
36         public string VirtualPath { get; set; }
37     }

VirtualPathData

 

 4.Route 

      命名空间:  System.Web.Routing

      属性:Url、RouteHandler 、Defaults 、DataTokens 、Constraints 

      方法:4个构造函数、ProcessConstraint、GetVirtualPath、GetRouteData

图片 10图片 11

  1  // 摘要: 
  2     //     提供用于定义路由及获取路由相关信息的属性和方法。
  3     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
  4     public class Route : RouteBase
  5     {
  6         // 摘要: 
  7         //     使用指定的 URL 模式和处理程序类初始化 System.Web.Routing.Route 类的新实例。
  8         //
  9         // 参数: 
 10         //   url:
 11         //     路由的 URL 模式。
 12         //
 13         //   routeHandler:
 14         //     处理路由请求的对象。
 15         public Route(string url, IRouteHandler routeHandler);
 16         //
 17         // 摘要: 
 18         //     使用指定的 URL 模式、默认参数值和处理程序类初始化 System.Web.Routing.Route 类的新实例。
 19         //
 20         // 参数: 
 21         //   url:
 22         //     路由的 URL 模式。
 23         //
 24         //   defaults:
 25         //     用于 URL 中缺失的任何参数的值。
 26         //
 27         //   routeHandler:
 28         //     处理路由请求的对象。
 29         public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
 30         //
 31         // 摘要: 
 32         //     使用指定的 URL 模式、默认参数值、约束和处理程序类初始化 System.Web.Routing.Route 类的新实例。
 33         //
 34         // 参数: 
 35         //   url:
 36         //     路由的 URL 模式。
 37         //
 38         //   defaults:
 39         //     要在 URL 不包含所有参数时使用的值。
 40         //
 41         //   constraints:
 42         //     一个用于指定 URL 参数的有效值的正则表达式。
 43         //
 44         //   routeHandler:
 45         //     处理路由请求的对象。
 46         public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
 47         //
 48         // 摘要: 
 49         //     使用指定的 URL 模式、默认参数值、约束、自定义值和处理程序类初始化 System.Web.Routing.Route 类的新实例。
 50         //
 51         // 参数: 
 52         //   url:
 53         //     路由的 URL 模式。
 54         //
 55         //   defaults:
 56         //     要在 URL 不包含所有参数时使用的值。
 57         //
 58         //   constraints:
 59         //     一个用于指定 URL 参数的有效值的正则表达式。
 60         //
 61         //   dataTokens:
 62         //     传递到路由处理程序但未用于确定该路由是否匹配特定 URL 模式的自定义值。 这些值会传递到路由处理程序,以便用于处理请求。
 63         //
 64         //   routeHandler:
 65         //     处理路由请求的对象。
 66         public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);
 67 
 68         // 摘要: 
 69         //     获取或设置为 URL 参数指定有效值的表达式的词典。
 70         //
 71         // 返回结果: 
 72         //     一个包含参数名称和表达式的对象。
 73         public RouteValueDictionary Constraints { get; set; }
 74         //
 75         // 摘要: 
 76         //     获取或设置传递到路由处理程序但未用于确定该路由是否匹配 URL 模式的自定义值。
 77         //
 78         // 返回结果: 
 79         //     一个包含自定义值的对象。
 80         public RouteValueDictionary DataTokens { get; set; }
 81         //
 82         // 摘要: 
 83         //     获取或设置要在 URL 不包含所有参数时使用的值。
 84         //
 85         // 返回结果: 
 86         //     一个包含参数名称和默认值的对象。
 87         public RouteValueDictionary Defaults { get; set; }
 88         //
 89         // 摘要: 
 90         //     获取或设置处理路由请求的对象。
 91         //
 92         // 返回结果: 
 93         //     处理请求的对象。
 94         public IRouteHandler RouteHandler { get; set; }
 95         //
 96         // 摘要: 
 97         //     获取或设置路由的 URL 模式。
 98         //
 99         // 返回结果: 
100         //     用于匹配路由和 URL 的模式。
101         //
102         // 异常: 
103         //   System.ArgumentException:
104         //     以下任一值: 以 ~ 或 / 开头的值。 包含 ? 字符的值。 “全部捕捉”参数不在末尾。
105         //
106         //   System.Exception:
107         //     没有使用分隔符或文字常量分隔 URL 分段。
108         public string Url { get; set; }
109 
110         // 摘要: 
111         //     返回有关所请求路由的信息。
112         //
113         // 参数: 
114         //   httpContext:
115         //     一个对象,封装有关 HTTP 请求的信息。
116         //
117         // 返回结果: 
118         //     一个对象,其中包含路由定义中的值。
119         public override RouteData GetRouteData(HttpContextBase httpContext);
120         //
121         // 摘要: 
122         //     返回与路由关联的 URL 的相关信息。
123         //
124         // 参数: 
125         //   requestContext:
126         //     一个对象,封装有关所请求的路由的信息。
127         //
128         //   values:
129         //     一个包含路由参数的对象。
130         //
131         // 返回结果: 
132         //     一个包含与路由关联的 URL 的相关信息的对象。
133         public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
134         //
135         // 摘要: 
136         //     确定参数值是否与该参数的约束匹配。
137         //
138         // 参数: 
139         //   httpContext:
140         //     一个对象,封装有关 HTTP 请求的信息。
141         //
142         //   constraint:
143         //     用于测试 parameterName 的正则表达式或对象。
144         //
145         //   parameterName:
146         //     要测试的参数的名称。
147         //
148         //   values:
149         //     要测试的值。
150         //
151         //   routeDirection:
152         //     一个指定 URL 路由是否处理传入请求或构造 URL 的值。
153         //
154         // 返回结果: 
155         //     如果参数值与约束匹配,则为 true;否则为 false。
156         //
157         // 异常: 
158         //   System.InvalidOperationException:
159         //     constraint 不是包含正则表达式的字符串。
160         protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
161     }

Route

 

5.RouteTable

      命名空间:  System.Web.Routing

      属性:Routes 

      方法:1个构造函数

图片 12图片 13

 1 // 摘要: 
 2     //     存储应用程序的 URL 路由。
 3     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
 4     public class RouteTable
 5     {
 6         // 摘要: 
 7         //     初始化 System.Web.Routing.RouteTable 类的新实例。
 8         public RouteTable();
 9 
10         // 摘要: 
11         //     获取从 System.Web.Routing.RouteBase 类派生的对象的集合。
12         //
13         // 返回结果: 
14         //     包含集合中的所有路由的对象。
15         public static RouteCollection Routes { get; }
16     }

RouteTable

 

1.3 注册路由映射:我们可以通过 RouteTable的静态属性 Routes得到一个基于整个应用的全局路由表。这是一个类型为RouteCollection的集合对象 ,可以通过调用它的 MapPageRoute进行路由映射 ,即注册路由模板与某个物理文件的匹配关系。路由注册的核心就是在全局路由表中添加一个Route对象,该对象的绝大部分属性都可以通过MapPageRoute方法的相关参数来指定。
接下来我们通过实例演示的方式来说明路由注册的— 些细节问题 。图片 14^_^


在路由注册中指定约束和默认值(constaints和defaults),示例:天气预报 的例子 S202 和 S203(S203中加入了对httpmethod的约束)
针对现有物理文件的路由(RouteTable.Routes.RouteExistingFiles),示例:天气预报 的例子 S204 和 S205(S204中RouteExistingFiles默认false,S205RouteExistingFiles为true)

RouteCollection和 Route的 RouteExistingFiles属性对路由的影响,示例:S206

注册需要被忽略的路由地址,示例:S207 和 S208 (S208中加了一段代码“RouteTable.Routes.Ignore("css/{filename}.css/{*pathInfo}");”为了让路由系统忽略对css文件的请求)

 

1.4 根据路出规则生成 URL:

 Asp.NET的 路由系统主要有两个方面的应用,—个就是通过注册路由模板与物理文件路径的映射实现请求地址和物理地址的分离;另一个则是通过注册的路由规则生成一个相应的 URL,后者可以通过调用 RouteCollection对象的 GetVirtrualPath方法来实现。
下面是一个示例:天气预报 S209

图片 15图片 16

 1 namespace WebApp
 2 {
 3     public partial class Weather : System.Web.UI.Page
 4     {
 5         protected void Page_Load(object sender, EventArgs e)
 6         {
 7             RouteData routeData = new RouteData();
 8             routeData.Values.Add("areaCode", "0512");
 9             routeData.Values.Add("days", "1");
10             RequestContext requestContext = new RequestContext();
11             requestContext.HttpContext = new HttpContextWrapper(HttpContext.Current);
12             requestContext.RouteData = routeData;
13 
14             RouteValueDictionary values = new RouteValueDictionary();
15             values.Add("areaCode", "028");
16             values.Add("days", "3");
17 
18             Response.Write(RouteTable.Routes.GetVirtualPath(null, null).VirtualPath+ "<br/>");
19             Response.Write(RouteTable.Routes.GetVirtualPath(requestContext,null).VirtualPath + "<br/>");
20             Response.Write(RouteTable.Routes.GetVirtualPath(requestContext,values).VirtualPath + "<br/>");
21         }
22     }
23 }

S209部分代码(重要部分)

从上面 的代码片段可以看到 ,第—次调用GetVirtrualPath方法传输的requestContext和values参数均为Null。第二次则指定了一个手工创建的RequestContext对象,其 RouteData的Values属性具有两个变量 (areaCode=0512,days=1),而values参数依然为 Null。第三次我们同时为参数requestContext和values指定了具体的对象,而后者包 含两个参数(areaCode=028,days=3)。
该实例最后现实的效果,如下图所示:
图片 17

1.5 HttpHandler的动态映射:

一般情况下一个请求最终是通过一个具体的 HttpHandler进行处理的。表示—个Web页面的Page对象就是一个 HttpHandler,它 被用于最终处理基于某个.aspx文件的请求。我们可以通过
HttpHandler的动态映射来实现请求地址与物理文件路径之间的分离。 Asp.Net的URL路由系统通过一个注册的HttpModule对象实现对请求进行的拦截,然后动态映射一个用于处理当前请求的 HttpHandler对象。HttpHandler对请求进行处理并予以响应 。

图片 18

 

 作为请求拦截器的HttpModule类型为System.Web.Routing.UrlRoutingModule.

 对于通过调用RouteCollection的MapPageRoute方法注册的Route来说,它的RouteHandler属性返回一个类型为System.Web.Routing.PageRouteHandler的对象。

PageRouteHandler的GetHttpHandler方法最终返回的就是针对映射页面文件路径的Page对象。

 

二、Asp.net Web API 路由

WebAPI的独立性在与它有一套自己的消息处理管道。作为消息处理管道的一部分,Asp.Net Web API 具有自己的路由系统,其路由采用与Asp.Net路由系统类似的设计。在下面的讲解中我们会发现定义在Asp.Net路由系统中的核心类型,在Asp.Net Web API的路由系统中均可以找到对应的类型。

 

请求与响应:

Asp.Net:                       有HttpContext      HttpRequest和HttpResponse                                命名空间:System.Web

Asp.Net Web API:          无HttpContext      HttpRequestMessage和HttpResponseMessage       命名空间:System.Net.Http

Asp.Net Web API的核心框架是一个独立抽象的消息处理管道.所以命名空间和所在的程序集也不同于Asp.Net.

 

1.HttpRequestMessage

命名空间: System.Net.Http

属性:Content、Headers、Method(默认为Get)、Properties、RequestUri、Version(默认值:System.Net.HttpVersion.Version11,表示为HTTP1.1)

方法:3个构造函数、Dispose、Dispose(带参虚方法)、ToString

  请求报文的报头集合和主体内容分别通过HttpRequestMessage的Headers和Content来表示。利用字典类型的只读属性Properties,我们可以将任意对象作为属性附加到一个HttpRequestMessage对象上。

 

图片 19图片 20

 1     // 摘要: 
 2     //     表示 HTTP 请求消息。
 3     public class HttpRequestMessage : IDisposable
 4     {
 5         // 摘要: 
 6         //     初始化 System.Net.Http.HttpRequestMessage 类的新实例。
 7         public HttpRequestMessage();
 8         //
 9         // 摘要: 
10         //     初始化 HTTP 方法和请求 System.Uri 的 System.Net.Http.HttpRequestMessage 类的新实例。
11         //
12         // 参数: 
13         //   method:
14         //     HTTP 方法。
15         //
16         //   requestUri:
17         //     表示请求 System.Uri 的字符串。
18         public HttpRequestMessage(HttpMethod method, string requestUri);
19         //
20         // 摘要: 
21         //     初始化 HTTP 方法和请求 System.Uri 的 System.Net.Http.HttpRequestMessage 类的新实例。
22         //
23         // 参数: 
24         //   method:
25         //     HTTP 方法。
26         //
27         //   requestUri:
28         //     要请求的 System.Uri。
29         public HttpRequestMessage(HttpMethod method, Uri requestUri);
30 
31         // 摘要: 
32         //     获取或设置 HTTP 消息的内容。
33         //
34         // 返回结果: 
35         //     返回 System.Net.Http.HttpContent。 消息的内容
36         public HttpContent Content { get; set; }
37         //
38         // 摘要: 
39         //     获取 HTTP 请求标头的集合。
40         //
41         // 返回结果: 
42         //     返回 System.Net.Http.Headers.HttpRequestHeaders。 HTTP 请求标头的集合。
43         public HttpRequestHeaders Headers { get; }
44         //
45         // 摘要: 
46         //     获取或设置 HTTP 请求信息使用的 HTTP 方法。
47         //
48         // 返回结果: 
49         //     返回 System.Net.Http.HttpMethod。 被请求消息使用的HTTP 方法。 GET 是默认方法。
50         public HttpMethod Method { get; set; }
51         //
52         // 摘要: 
53         //     获取 HTTP 请求的属性集。
54         //
55         // 返回结果: 
56         //     返回 System.Collections.Generic.IDictionary<TKey,TValue>。
57         public IDictionary<string, object> Properties { get; }
58         //
59         // 摘要: 
60         //     获取或设置 HTTP 请求的 System.Uri。
61         //
62         // 返回结果: 
63         //     返回 System.Uri。 用于 HTTP 请求的 System.Uri。
64         public Uri RequestUri { get; set; }
65         //
66         // 摘要: 
67         //     获取或设置 HTTP 消息版本。
68         //
69         // 返回结果: 
70         //     返回 System.Version。 HTTP 消息版本。 默认值为 1.1。
71         public Version Version { get; set; }
72 
73         // 摘要: 
74         //     释放由 System.Net.Http.HttpRequestMessage 使用的非托管资源和托管资源。
75         public void Dispose();
76         //
77         // 摘要: 
78         //     释放由 System.Net.Http.HttpRequestMessage 使用的非托管资源,并可根据需要释放托管资源。
79         //
80         // 参数: 
81         //   disposing:
82         //     如果为 true,则释放托管资源和非托管资源;如果为 false,则仅释放非托管资源。
83         protected virtual void Dispose(bool disposing);
84         //
85         // 摘要: 
86         //     返回表示当前对象的字符串。
87         //
88         // 返回结果: 
89         //     返回 System.String。 当前对象的字符串表示形式。
90         public override string ToString();
91     }

HttpRequestMessage

上一篇:C核心 那些个关键字 下一篇:没有了