程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 8 Store Apps學習(61) 通信: http, oauth

Windows 8 Store Apps學習(61) 通信: http, oauth

編輯:關於.NET

介紹

重新想象 Windows 8 Store Apps 之 通信

HttpClient 概述

http get string

http get stream

http post string

http post stream

OAuth 2.0 驗證的客戶端

示例

用於演示 http 通信的服務端

WebServer/HttpDemo.aspx.cs

/*
 * 用於響應 http 請求
 */
    
using System;
using System.IO;
using System.Threading;
    
namespace WebServer
{
    public partial class HttpDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // 停 3 秒,以方便測試 http 請求的取消
            Thread.Sleep(3000);
    
            var action = Request.QueryString["action"];
    
            switch (action)
            {
                case "getString": // 響應 http get string 
                    Response.Write("hello webabcd");
                    break;
                case "getStream": // 響應 http get stream 
                    Response.Write("hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd");
                    break;
                case "postString": // 響應 http post string 
                    Response.Write(string.Format("param1:{0}, param2:{1}, referrer:{2}", Request.Form["param1"], Request.Form["param2"], Request.UrlReferrer));
                    break;
                case "postStream": // 響應 http post stream 
                    using (StreamReader reader = new StreamReader(Request.InputStream))
                    {
                        string body = reader.ReadToEnd();
                        Response.Write(Server.HtmlEncode(body));
                    }
                    break;
                default:
                    break;
            }
    
            Response.End();
        }
    }
}

1、通過 HttpClient, HttpRequestMessage, HttpResponseMessage 實現 HTTP 通信

Communication/HTTP/Summary.xaml

<Page
    x:Class="XamlDemo.Communication.HTTP.Summary"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.HTTP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">
    
            <TextBlock Name="lblMsg" FontSize="14.667" />
    
            <Button Name="btnPost" Content="http post" Click="btnPost_Click_1" Margin="0 10 0 0" />
    
            <Button Name="btnCancel" Content="cancel" 

Click="btnCancel_Click_1" Margin="0 10 0 0" />
    
        </StackPanel>
    </Grid>
</Page>

Communication/HTTP/Summary.xaml.cs

/*
 * 通過 HttpClient, HttpRequestMessage, HttpResponseMessage 實現 HTTP 通信
 * 
 * HttpClient - 用於發起 http 請求,以及接收 http 響應
 *     BaseAddress - 發送請求的 uri
 *     DefaultRequestHeaders - 默認的 http 請求頭信息
 *     MaxResponseContentBufferSize - 讀取響應內容時,所可以緩沖的最大字節數。默

認值:64K
 *     Timeout - http 請求的超時時間
 *     CancelPendingRequests() - 取消該 HttpClient 對象所有掛起的 http 請求
 *     GetStringAsync(), GetStreamAsync(), GetByteArrayAsync(), GetAsync() - http 

get 數據
 *     PostAsync(), DeleteAsync(), PutAsync() - http post delete put 數據
 *         參數:HttpContent content - http 請求的數據(HttpContent 類型)
 *             繼承自 HttpContent 的類有:StringContent, ByteArrayContent, 

StreamContent, FormUrlEncodedContent 等
 *         參數:HttpCompletionOption completionOption(HttpCompletionOption 枚舉

)
 *             ResponseContentRead - 獲取到全部內容後再返回數據,默認值
 *             ResponseHeadersRead - 獲取到頭信息後就返回數據,用於流式獲取
 * 
 * HttpRequestMessage - http 請求
 *     Method - http 方法
 *     RequestUri - 請求的 uri
 *     Version - http 版本,默認是 1.1
 *     Headers - http 的請求頭信息
 *     Content - http 請求的內容(HttpContent 類型)
 *         繼承自 HttpContent 的類有:StringContent, ByteArrayContent, 

StreamContent, FormUrlEncodedContent 等
 *         
 * HttpResponseMessage - http 響應
 *     RequestMessage - 對應的 HttpRequestMessage 對象
 *     Headers - http 的響應頭信息
 *     Version - http 版本,默認是 1.1
 *     StatusCode - http 響應的狀態碼
 *     ReasonPhrase - http 響應的狀態碼所對應的短語
 *     IsSuccessStatusCode - http 響應的狀態碼是否是成功的值(200-299)
 *     EnsureSuccessStatusCode() - 當 IsSuccessStatusCode 為 false 時會拋出異常
 *     
 * 
 * 注:關於下載/上傳的進度獲取,請參見“後台任務”
 * 
 * 另:win8 metro 的 http 抓包可用 fiddler
 * 
 * 還有:
 * http 通信還可以通過如下方法實現
 * HttpWebRequest webRequest = WebRequest.Create(url);
 */
    
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
    
namespace XamlDemo.Communication.HTTP
{
    public sealed partial class Summary : Page
    {
        private HttpClient _httpClient;
    
        public Summary()
        {
            this.InitializeComponent();
        }
    
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 釋放資源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }
    
        private async void btnPost_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();
    
            try
            {
                string url = "http://localhost:39629/HttpDemo.aspx?action=postString";
                // 創建一個 HttpRequestMessage 對象
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
    
                // 需要 post 的數據
                var postData = new FormUrlEncodedContent(
                    new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>("param1", "web"),
                        new KeyValuePair<string, string>("param2", "abcd")
                    }
                );
    
                // http 請求的數據
                request.Content = postData;
                // http 請求的頭信息
                request.Headers.Referrer = new Uri("http://webabcd.cnblogs.com");
    
                // 請求 HttpRequestMessage 對象,並返回 HttpResponseMessage 數據
                HttpResponseMessage response = await _httpClient.SendAsync(request);
    
                // http 響應的狀態碼及其對應的短語
                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;
    
                // 以字符串的方式獲取響應數據
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 請求
            _httpClient.CancelPendingRequests();
        }
    }
}

2、演示 http get string

Communication/HTTP/GetString.xaml.cs

/*
 * 演示 http get string
 */
    
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
    
namespace XamlDemo.Communication.HTTP
{
    public sealed partial class GetString : Page
    {
        private HttpClient _httpClient;
    
        public GetString()
        {
            this.InitializeComponent();
        }
    
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 釋放資源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }
    
        private async void btnGetString_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();
    
            try
            {
                HttpResponseMessage response = await _httpClient.GetAsync(new Uri("http://localhost:39629/HttpDemo.aspx?action=getString"));
    
                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;
    
                // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
             catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 請求
            _httpClient.CancelPendingRequests();
        }
    }
}

3、演示 http get stream

Communication/HTTP/GetStream.xaml.cs

/*
 * 演示 http get stream
 */
    
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
    
namespace XamlDemo.Communication.HTTP
{
    public sealed partial class GetStream : Page
    {
        private HttpClient _httpClient;
    
        public GetStream()
        {
            this.InitializeComponent();
        }
    
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 釋放資源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }
    
        private async void btnGetStream_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();
    
            try
            {
                // HttpCompletionOption.ResponseHeadersRead - 獲取到頭信息後就返回數據,用於流式獲取
                HttpResponseMessage response = await _httpClient.GetAsync(
                    new Uri("http://localhost:39629/HttpDemo.aspx?action=getStream"), 
                    HttpCompletionOption.ResponseHeadersRead);
    
                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;
    
                // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據
                using (Stream responseStream = await response.Content.ReadAsStreamAsync())
                {
                    byte[] buffer = new byte[32];
                    int read = 0;
    

                    while ((read = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        lblMsg.Text += "讀取的字節數: " + read.ToString();
                        lblMsg.Text += Environment.NewLine;
    
                        IBuffer responseBuffer = CryptographicBuffer.CreateFromByteArray(buffer);
                        lblMsg.Text += CryptographicBuffer.EncodeToHexString(responseBuffer);
                        lblMsg.Text += Environment.NewLine;
    
                        buffer = new byte[32];
                    }
                }
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
             catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 請求
            _httpClient.CancelPendingRequests();
        }
    }
}

4、演示 http post string

Communication/HTTP/PostString.xaml.cs

/*
 * 演示 http post string
 */
    
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
    
namespace XamlDemo.Communication.HTTP
{
    public sealed partial class PostString : Page
    {
        private HttpClient _httpClient;
    
        public PostString()
        {
            this.InitializeComponent();
        }
    
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 釋放資源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }
    
        private async void btnPostString_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();
    
            try
            {
                // 需要 post 的數據
                var postData = new FormUrlEncodedContent(
                    new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>("param1", "web"),
                        new KeyValuePair<string, string>("param2", "abcd")
                    } 
                );
    
                HttpResponseMessage response = await _httpClient.PostAsync(
                    new Uri("http://localhost:39629/HttpDemo.aspx?action=postString"),
                    postData);
    
                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;
    
                // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 請求
            _httpClient.CancelPendingRequests();
        }
    }
}

5、演示 http post stream

Communication/HTTP/PostStream.xaml.cs

/*
 * 演示 http post stream
 */
    
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
    
namespace XamlDemo.Communication.HTTP
{
    public sealed partial class PostStream : Page
    {
        private HttpClient _httpClient;
    
        public PostStream()
        {
            this.InitializeComponent();
        }
    
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // 釋放資源
            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }
    
        private async void btnPostStream_Click_1(object sender, RoutedEventArgs e)
        {
            _httpClient = new HttpClient();
    
            try
            {
                // 需要 post 的 stream 數據
                Stream stream = GenerateSampleStream(128);
                StreamContent streamContent = new StreamContent(stream);
    
                HttpResponseMessage response = await _httpClient.PostAsync(
                   new Uri("http://localhost:39629/HttpDemo.aspx?action=postStream"),
                   streamContent);
    
                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;
                lblMsg.Text += Environment.NewLine;
    
                // HttpContent.ReadAsStringAsync() - 以 string 方式獲取響應數據
                // HttpContent.ReadAsByteArrayAsync() - 以 byte[] 方式獲取響應數據
                // HttpContent.ReadAsStreamAsync() - 以 stream 方式獲取響應數據
                lblMsg.Text += await response.Content.ReadAsStringAsync();
                lblMsg.Text += Environment.NewLine;
            }
            catch (TaskCanceledException)
            {
                lblMsg.Text += "取消了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // 生成一個指定大小的內存流
        private static MemoryStream GenerateSampleStream(int size)
        {
            byte[] subData = new byte[size];
            for (int i = 0; i < subData.Length; i++)
            {
                subData[i] = (byte)(97 + i % 26); // a-z
            }
    
            return new MemoryStream(subData);
        }
    
        private void btnCancel_Click_1(object sender, RoutedEventArgs e)
        {
            // 取消 http 請求
            _httpClient.CancelPendingRequests();
        }
    }
}

6、演示如何開發一個基於 OAuth 2.0 驗證的客戶端

Communication/OpenAuth/ClientDemo.xaml

<Page
    x:Class="XamlDemo.Communication.OpenAuth.ClientDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.OpenAuth"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">
    
            <Button Name="btnWeibo" Content="登錄新浪微博,並返回登錄用戶好友最新發布的微博" Click="btnWeibo_Click" />
    
            <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" Margin="0 10 0 0" />
    
        </StackPanel>
    </Grid>
</Page>

查看本欄目

Communication/OpenAuth/ClientDemo.xaml.cs

/*
 * 演示如何開發一個基於 OAuth 2.0 驗證的客戶端
 * 
 * WebAuthenticationBroker - 用於 OAuth 2.0 驗證的第一步,可以將第三方 UI 無縫整

合進 app
 *     AuthenticateAsync(WebAuthenticationOptions options, Uri requestUri, Uri 

callbackUri) - 請求 authorization code,返回一個 WebAuthenticationResult 類型的數

據
 *
 * WebAuthenticationResult - 請求 authorization code(OAuth 2.0 驗證的第一步)的

結果
 *     ResponseData - 響應的數據         
 *     ResponseStatus - 響應的狀態
 *     
 * 
 * 關於 OAuth 2.0 協議參見:http://tools.ietf.org/html/draft-ietf-oauth-v2-20
 */
    
using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using Windows.Data.Json;
using Windows.Security.Authentication.Web;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
    
namespace XamlDemo.Communication.OpenAuth
{
    public sealed partial class ClientDemo : Page
    {
        public ClientDemo()
        {
            this.InitializeComponent();
        }
    
        private async void btnWeibo_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var appKey = "39261162";
                var appSecret = "652ec0b02f814d514fc288f3eab2efda";
                var callbackUrl = "http://webabcd.cnblogs.com"; // 在新浪微博開放平台設置的回調頁
    
                var requestAuthorizationCode_url = 
                    string.Format("https://api.weibo.com/oauth2/authorize?client_id={0}&response_type=code&redirect_uri={1}", 
                    appKey, 
                    callbackUrl);
    
                // 第一步:request authorization code
                WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
                    WebAuthenticationOptions.None,
                    new Uri(requestAuthorizationCode_url),
                    new Uri(callbackUrl));
    
                // 第一步的結果
                lblMsg.Text = WebAuthenticationResult.ResponseStatus.ToString() + Environment.NewLine;
    
                if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
                {
                    // 從第一步返回的數據中獲取 authorization code
                    var authorizationCode = QueryString(WebAuthenticationResult.ResponseData, "code");
                    lblMsg.Text += "authorizationCode: " + authorizationCode + Environment.NewLine;
    
                    var requestAccessToken_url =
                        string.Format("https://api.weibo.com/oauth2/access_token?client_id={0}&client_secret={1}&grant_type=authorization_code&redirect_uri={2}&code={3}", 
                        appKey, 
                        appSecret,
                        callbackUrl,
                        authorizationCode);
    
                    // 第二步:request access token
                    HttpClient client = new HttpClient();
                    var response = await client.PostAsync(new Uri(requestAccessToken_url), null);
    
                    // 第二步的結果:獲取其中的 access token
                    var jsonString = await response.Content.ReadAsStringAsync();
                    JsonObject jsonObject = JsonObject.Parse(jsonString);
                    var accessToken = jsonObject["access_token"].GetString();
                    lblMsg.Text += "accessToken: " + accessToken + Environment.NewLine;
    
                    var requestProtectedResource_url =
                        string.Format("https://api.weibo.com/2/statuses/friends_timeline.json?access_token={0}", 
                        accessToken);
    
                    // 第三步:request protected resource,獲取需要的數據(本例為獲取登錄用戶好友最新發布的微博)
                    var result = await client.GetStringAsync(new Uri(requestProtectedResource_url));
                    lblMsg.Text += "result: " + result;
                }
            }
            catch (Exception ex)
            {
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
    
                // 由於本 app 沒有提交新浪微博開放平台審核,所以需要在新浪微博開放平台中添加測試賬號,否則會出現異常
            }
        }
    
        /// <summary>
        /// 模擬 QueryString 的實現
        /// </summary>
        /// <param name="queryString">query 字符串</param>
        /// <param name="key">key</param>
        private string QueryString(string queryString, string key)
        {
            return Regex.Match(queryString, string.Format(@"(?<=(\&|\?|^)({0})\=).*?(?=\&|$)", key), RegexOptions.IgnoreCase).Value;
        }  
    }
}
    
/*
 * OAuth 2.0 的 Protocol Flow
     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
*/

OK

[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved