关于ASP.NET WebAPI中HTTP模型的相关思考
对于.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中HTTP模型的相关思考的更多相关文章
- Asp.net Mvc 中的模型绑定
asp.net mvc中的模型绑定可以在提交http请求的时候,进行数据的映射. 1.没有模型绑定的时候 public ActionResult Example0() { ) { string id ...
- ASP.NET Core 中的模型绑定
微软官方文档:ASP.NET Core 中的模型绑定 Route 是通过MVC Route URL取值. 如:http://localhost:5000/Home/Index/2,id取出的值就会是2 ...
- 在asp.net WebAPI 中 使用Forms认证和ModelValidata(模型验证)
一.Forms认证 1.在webapi项目中启用Forms认证 Why:为什么要在WebAPI中使用Forms认证?因为其它项目使用的是Forms认证. What:什么是Forms认证?它在WebAP ...
- [翻译] ASP.NET WebAPI 中的异常处理
原文链接:https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling 本文介绍 ...
- ASP.NET WebApi 中使用swagger 构建在线帮助文档
1 在Visual Studio 中创建一个Asp.NET WebApi 项目,项目名:Com.App.SysApi(本例创建的是 .net 4.5 框架程序) 2 打开Nuget 包管理软件,查 ...
- 在ASP.NET WebAPI 中使用缓存【Redis】
初步看了下CacheCow与OutputCache,感觉还是CacheOutput比较符合自己的要求,使用也很简单 PM>Install-Package Strathweb.CacheOutpu ...
- ASP.NET MVC中的模型装配 封装方法 非常好用
下面说一下 我们知道在asp.net mvc中 视图可以绑定一个实体模型 然后我们三层架构中也有一个model模型 但是这两个很多时候却是不一样的对象来的 就拿微软的官方mvc例子来说明 微软的视图实 ...
- Asp.Net WebAPI 中Cookie 获取操作方式
1. /// <summary> /// 获取上下文中的cookie /// </summary> /// <returns></returns> [H ...
- Asp.Net WebAPI中Filter过滤器的使用以及执行顺序
转发自:http://www.cnblogs.com/UliiAn/p/5402146.html 在WEB Api中,引入了面向切面编程(AOP)的思想,在某些特定的位置可以插入特定的Filter进行 ...
随机推荐
- WimMaker 2.0 (2013.10) WIM制作工具
WimMaker 2.0 (2013.10) WIM制作工具 可用于制作PE启动内核的Wim文件 说明: 因本软件使用.NET2.0制作,故主要用于制作WIM映像不用于备份还原系统(虽可用,但不专业, ...
- jquery+ligerform三级联动下拉框
如下为ligerform里的三级联动下拉框: var formData=[ {display:,width:,space:,type:"select",group:"区域 ...
- 基于Quqrtz.NET 做的任务调度管理工具
基于Quqrtz.NET 做的任务调度管理工具 国庆前,需求让我看了一下任务调度的数据表设计.和之前一样,有100多个字段,p1 ~ p100, 我说这是干嘛啊!按这写,写死去了! 然后在网上搜了一下 ...
- J2EE开发HelloWorld
J2EE开发实战基础系列一 HelloWorld 开始咱们的第一个程序,首先是配置环境,按照上一章所描述的方式下载开发工具,然后配置Java环境变量,给大家看下具体的结构: 环境变量配置OK的提示,如 ...
- Varnish 4.0
Varnish 4.0 实战 简介 Varnish 是一款高性能且开源的反向代理服务器和 HTTP 加速器,其采用全新的软件体系机构,和现在的硬件体系紧密配合,与传统的 squid 相比,varn ...
- Ubuntu下安装Python绘图库Matplotlib的方法
在安装好Python的基础上, sudo apt-get install python-numpy sudo apt-get install python-scipy sudo apt-get ins ...
- MVC视图中的@Html.xxx(...)
ASP.NET MVC视图中的@Html.xxx(...) 问题 在视图页中@Html.xxx(...)是什么?如何被执行? 如下图所示: 解疑 视图页中@Html.xxx(...)涉及的内容有: ...
- C++虚函数表调用学习
知识点是看 陈皓大哥的博客,代码也参考了他的,不过做了很小的改动. 原文链接:http://blog.csdn.net/haoel/article/details/1948051 #include & ...
- ASP.NET WEB API构建基于REST风格
使用ASP.NET WEB API构建基于REST风格的服务实战系列教程[开篇] 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http ...
- MAKE gnu
GNU Make 学习系列一:怎样写一个简单的Makefile 编程通常遵循一个相当简单的程序:编辑源文件,编译源代码成可执行的格式,调试结果.尽管将源代码翻译成可执行程序是常规的过程,如果做的不正确 ...