zoukankan      html  css  js  c++  java
  • 重新想象 Windows 8 Store Apps (61)

    [源码下载]


    重新想象 Windows 8 Store Apps (61) - 通信: http, oauth



    作者:webabcd


    介绍
    重新想象 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
    [源码下载]

  • 相关阅读:
    What is "Type" in managed heap?
    SQL Server 2005:一个使用新创建的User的问题和解决方法
    如何证明Application Domain的隔离性
    我的WCF之旅(10):如何在WCF进行Exception Handling
    SQLXML初体验:用XML代替TSQL来操作数据库
    我的WCF之旅(3):在WCF中实现双工通信
    我的WCF之旅(4):WCF中的序列化[下篇]
    再说String
    谈谈基于Kerberos的Windows Network Authentication[上篇]
    我所理解的Remoting(1):Marshaling & Activation[上篇]
  • 原文地址:https://www.cnblogs.com/webabcd/p/3334233.html
Copyright © 2011-2022 走看看