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

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

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

一.WebAPI的HTTP概述:

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

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

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

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

      (1).在客户端和服务器端使用一样的类。(HttpRequestMessage和HttpResponseMessage对象中不包含上下文消息,因此能够在服务器和客户端共用。)app

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

      在获取原始消息内容时,除了调用上面介绍的方法外,还能够调用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, 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;
        }

   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以后的版本中,对象的使用没有客户端和服务器之分,二者能够共用。

相关文章
相关标签/搜索