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

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

一.WebAPI的HTTP概述:

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

http://www.cnblogs.com/pengze0902/p/5976388.html

http://www.cnblogs.com/pengze0902/p/6224792.html

http://www.cnblogs.com/pengze0902/p/6230105.html

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请求和响应对象的访问。

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

二.WebAPI的HTTP消息解析:

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

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

以上主要讲解了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>。当消息在服务器或者客户端本地进行处理时,该属性用于保存附加的消息信息。该属性只是一个通用的容器,保存本地消息属性。(与接受消息的连接相关的客户端认证;将消息与配置路由进行匹配,得到的路由数据)

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) )) || (value > ((HttpStatusCode) 0x3e7)))
{
throw new ArgumentOutOfRangeException("value");
}
this.CheckDisposed();
this.statusCode = value;
}
}

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

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方法还会验证标头是否可以有多个值。

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(), , (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()方法解析:

在获取原始消息内容时,除了调用上面介绍的方法外,还可以调用ReadAsStreamAsync()方法以拉取的方式访问原始的消息内容。

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

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

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

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

四.总结:

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

Asp.Net WebAPI核心对象解析(三)的更多相关文章

  1. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  2. Asp.Net WebApi核心对象解析(二)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  3. Asp.Net WebApi核心对象解析

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  4. Asp.Net WebApi核心对象解析(上篇)

    生活需要自己慢慢去体验和思考,对于知识也是如此.匆匆忙忙的生活,让人不知道自己一天到晚都在干些什么,似乎每天都在忙,但又好似不知道自己到底在忙些什么.不过也无所谓,只要我们知道最后想要什么就行.不管怎 ...

  5. Asp.Net WebApi核心对象解析(一)

    生活需要自己慢慢去体验和思考,对于知识也是如此.匆匆忙忙的生活,让人不知道自己一天到晚都在干些什么,似乎每天都在忙,但又好似不知道自己到底在忙些什么.不过也无所谓,只要我们知道最后想要什么就行.不管怎 ...

  6. asp.net core 核心对象解析

    首先声明这篇文章的所有内容均来自https://www.cnblogs.com/artech/p/inside-asp-net-core-framework.html ----感谢大内老A(artec ...

  7. ASP.NET Ajax核心对象

    本章学习目标 主要掌握AJAX的基本概念和实现机制,学习并创建XMLHttpRequest对象,使用XMLHttpRequestObject对象获取服务器端的数据 主要内容如下,请点击ASP.NET ...

  8. Asp.Net的核心对象

    原文地址:http://www.cnblogs.com/fish-li/archive/2011/08/21/2148640.html 1.HttpRuntime 对象在处理Http请求的asp.ne ...

  9. ASP.NET Core的路由[2]:路由系统的核心对象——Router

    ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...

随机推荐

  1. python脚本处理下载的b站学习视频

    作为常年在b站学习的我,一直以来看到有兴趣的视频,从来都是点赞收藏下载三连,但是苦于我那小钢炮iphone se屏幕大小有限,看起视频实在费劲,决定一定要找个下载电脑上下载b站视频的方法,以前用过硕鼠 ...

  2. 微信小程序开发——使用mock数据模拟api请求

    前言: 微信小程序开发中,后端提供了接口设计文档,前端可以先mock数据模拟api请求进行开发调试,而且可以根据需要设计mock文件的格式和内容,这样在后端接口开发完成之前,前端可以最大限度的完成前端 ...

  3. 51单片机学习笔记(清翔版)(21)——ADDA数模转换

    A:anolog模拟的         D:digital数字的 AD模拟转数字,DA数字转模拟 生活中的基本都是模拟量,如温度,可以是10℃,10.1℃等 手机的背光亮度自动调节,拿到太阳光下,亮度 ...

  4. ES查询-match VS match_phrase

    我们以一个查询的示例开始,我们在student这个type中存储了一些学生的基本信息,我们分别使用match和match_phrase进行查询. 首先,使用match进行检索,关键字是“He is”: ...

  5. Unity3D UI适配

    直接贴图

  6. 每天写两个的java常见面试题—final 和static 的用法

    第一次写随笔,可能写的比较乱,更多的是作为自己记忆一些知识的方式.所有记录的东西都是自己的一些理解,很多语言可能还是从其他大牛的博客里面搬过来的. 一.static的作用: static的的作用从三个 ...

  7. 【Java】学习笔记(1)

    Java数据类型: 基本数据类型:(变量在栈中)数值型:byte(1个字节) short(2个字节) int(四个字节) long(8个字节) ,float(4字节) double(8字节) 字符型: ...

  8. 关于get和post请求的区别

    1.标准答案 GET在浏览器回退时是无害的,而POST会再次提交请求. GET产生的URL地址可以被Bookmark,而POST不可以. GET请求会被浏览器主动cache,而POST不会,除非手动设 ...

  9. python的语法小结

    break 与continue的区别: 1.break是直接中断全部循环 2.continue则是在只不执行此次所循环的东西,其它循环依旧执行,比方说只是跳过第4次循环,第5次循环照常进行. \n 表 ...

  10. Python从入门到精通之Second!

    初识Python基础! -基础     -扩展名可以是任意的,但是导入模块时,如果不是.py文件就会报错. -两种执行方式      1.python解释器       文件名.py 文件路径 -Li ...