LoginSignup
9
9

More than 5 years have passed since last update.

WinRT (Windows Storeアプリ)でAsync/Await HTTP Clientサンプルを作ってみた

Last updated at Posted at 2015-01-31

WinRT HTTP ClientのUtility化

 WinRTのasync/await(非同期)で,HTTP Get/Postリクエストを発行するコードは紋切り型ですので,Utility化したクラスを作ってみました。

HttpUtilityの機能について

 HttpUtilityの機能は6個です。

  1. async/awaitの非同期型
  2. Proxy認証対応
  3. レスポンスのシリアライズ化が可能(Object<->JSON変換)
  4. HTTPレスポンスで自動デコード
  5. ネットワークの接続状態を自動確認してリクエスト発行
  6. WinRTライブラリでビルド可能

 JSONのシリアライズ/デシリアライズ化はStackOverflowの記事が良いです。
 ‡StackOvefflow, "How do I de/serialize JSON in WinRT?," http://stackoverflow.com/questions/10965829/how-do-i-de-serialize-json-in-winrt

使い方

HttpUtilityTest.cs

[TestMethod, TestCategory("Normal")]
public async Task GetAsyncTest()
{
    // arrange
    var uri = new Uri("https://www.google.com/");
    var expected = (int)HttpStatusCode.OK;

    // act
    var task = HttpUtil.GetAsync(uri);
    var result = await task;

    // assert
    Assert.AreEqual(expected, result.StatusCode);
}

[TestMethod, TestCategory("Normal")]
public async Task PostAsyncTest()
{
    // arrange
    var uri = new Uri("http://www.youtube.com/results");
    var content = "search_query=visualstudio";
    var expected = (int)HttpStatusCode.OK;

    // act
    var task = HttpUtil.PostAsync(uri, content);
    var result = await task;

    // assert
    Assert.AreEqual(expected, result.StatusCode);
}

ソースコード

 GitHubに掲載しました。
 ‡GitHub, "HttpUtility," https://github.com/k--kato/HttpUtility

HttpUtilityサンプルアプリ

 入力したキーワードで電子書籍ストア「honto」を検索し,HTMLの解析結果をGridViewで表示します。

BookMantion.png

機能

サンプルアプリ画面(XAML)は,Windowsストアアプリ開発の基本的な機能を搭載していますので,ぜひ参考にしてみてください。

  1. レスポンシブデザイン (解像度変更・画面回転に強い)
  2. Googleサジェスト(予測変換)に対応
  3. 簡単な自動テストコードがある
  4. ソート
  5. 検索履歴
  6. ポップアップメニュー
  7. 設定コントラクト
  8. 共有コントラクト

ソースコード

 GitHubに掲載しました。

 ‡GitHub, "BookMansion," https://github.com/k--kato/BookMantion/

付録(HttpUtilityソースコード一部)

HttpUtil.cs
using HttpUtillity.Const;
using HttpUtillity.Model;
using HttpUtillity.UtilException;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;

namespace HttpUtillity.Util
{
    public sealed class HttpUtil
    {
        #region > Public Method

        public static IAsyncOperation<HttpResponseEntity> PostAsync(Uri uri, string content)
        {
            return SendRequest(uri, HttpMethod.Post, content).AsAsyncOperation<HttpResponseEntity>();
        }

        public static IAsyncOperation<HttpResponseEntity> PostAsync(Uri uri, string username, string password, string content)
        {
            return SendRequest(uri, HttpMethod.Post, content, username, password).AsAsyncOperation<HttpResponseEntity>();
        }

        public static IAsyncOperation<HttpResponseEntity> GetAsync(Uri uri)
        {
            return SendRequest(uri, HttpMethod.Get).AsAsyncOperation<HttpResponseEntity>();
        }

        public static IAsyncOperation<HttpResponseEntity> GetAsync(Uri uri, string username, string password)
        {
            return SendRequest(uri, HttpMethod.Get, null, username, password).AsAsyncOperation<HttpResponseEntity>();
        }

        #endregion

        #region > Private Method

        private async static Task<HttpResponseEntity> SendRequest(Uri uri, HttpMethod method, string content = null, string username = null, string password = null)
        {
            /**********************************************************************
             * Validation
             **********************************************************************/
            if (!NetworkUtil.IsNetworkAvailable())
            {
                throw new HttpException(HttpUtilExceptionType.Internet);
            }

            /**********************************************************************
             * Initialize
             **********************************************************************/
            HttpClientHandler handler = new HttpClientHandler()
            {
                Proxy = WebRequest.DefaultWebProxy,
                UseProxy = true,
                UseCookies = true,
                PreAuthenticate = false,
                AllowAutoRedirect = true,
                UseDefaultCredentials = false,
                AutomaticDecompression = System.Net.DecompressionMethods.GZip,
                MaxAutomaticRedirections = 50,
                MaxRequestContentBufferSize = 2147483647,
            };

            /**********************************************************************
             * Proxy
             **********************************************************************/
            bool isNeedProxyCredential = !String.IsNullOrEmpty(username) &&
                                         !String.IsNullOrEmpty(password);
            if (isNeedProxyCredential)
            {
                handler.Credentials = new NetworkCredential(username, password);
            }

            /**********************************************************************
             * Timeout
             **********************************************************************/
            HttpClient client = new HttpClient(handler)
            {
                Timeout = TimeSpan.FromMilliseconds(DefaultValue.Timeout),
            };

            /**********************************************************************
             * Make Request
             **********************************************************************/
            HttpRequestMessage request = new HttpRequestMessage()
            {
                Method = method,
                RequestUri = uri,
            };

            if (method == HttpMethod.Post)
            {
                request.Content = new StringContent(content, Encoding.UTF8);
            }

            /**********************************************************************
             * Send HTTP Request
             **********************************************************************/
            try
            {
                HttpResponseMessage response = await client.SendAsync(request);
                return await ToHttpResponseEntity(response, content);
            }
            catch (HttpRequestException ex)
            {
                return ToHttpResponseEntity(ex);
            }
            catch (TaskCanceledException)
            {
                throw new HttpException(HttpUtilExceptionType.Timeout);
            }
        }

        private static async Task<HttpResponseEntity> ToHttpResponseEntity(HttpResponseMessage response, string content)
        {
            /**********************************************************************
             * Response Message
             **********************************************************************/
            HttpResponseEntity result = new HttpResponseEntity()
            {
                Version = response.Version.ToString(),
                StatusCode = (int)response.StatusCode,
                ReasonPhrase = response.ReasonPhrase,
                IsSuccessStatusCode = response.IsSuccessStatusCode,
            };

            result.Headers = new Dictionary<string, IEnumerable<string>>();
            foreach (var row in response.Headers)
            {
                result.Headers.Add(row.Key, row.Value);
            }

            using (Stream responseStream = await response.Content.ReadAsStreamAsync())
            {
                Encoding charset = Encoding.GetEncoding(response.Content.Headers.ContentType.CharSet);
                result.Content = new StreamReader(responseStream, charset).ReadToEnd();
                result.ContentType = response.Content.Headers.ContentType.ToString();
                result.ContentLength = (response.Content.Headers.ContentLength != null) ? (long)response.Content.Headers.ContentLength : 0;
            }

            /**********************************************************************
             * Request Message
             **********************************************************************/
            result.RequestMessage = new HttpRequestEntity()
            {
                Method = response.RequestMessage.Method.ToString(),
                Version = response.RequestMessage.Version.ToString(),
                Properties = response.RequestMessage.Properties,
                RequestUri = response.RequestMessage.RequestUri,
            };

            result.RequestMessage.Headers = new Dictionary<string, IEnumerable<string>>();
            foreach (var row in response.RequestMessage.Headers)
            {
                result.RequestMessage.Headers.Add(row.Key, row.Value);
            }

            if (response.RequestMessage.Content != null)
            {
                result.RequestMessage.Content = content;
                result.RequestMessage.ContentType = response.RequestMessage.Content.Headers.ContentType.ToString();
                result.RequestMessage.ContentLength = (response.RequestMessage.Content.Headers.ContentLength != null) ? (long)response.RequestMessage.Content.Headers.ContentLength : 0;
            }

            return result;
        }

        private static HttpResponseEntity ToHttpResponseEntity(HttpRequestException exception)
        {
            WebException webexception = exception.InnerException as WebException;

            /**********************************************************************
             * Response Message
             **********************************************************************/
            HttpResponseEntity result = new HttpResponseEntity()
            {
                ReasonPhrase = webexception.Status.ToString()
            };

            if (webexception.Response == null)
            {
                throw new HttpException(HttpUtilExceptionType.Dns);
            }

            result.ContentLength = webexception.Response.ContentLength;
            result.ContentType = webexception.Response.ContentType;
            result.Headers = new Dictionary<string, IEnumerable<string>>();
            foreach (string key in webexception.Response.Headers.AllKeys)
            {
                IEnumerable<string> value = new List<string>(1) { webexception.Response.Headers[key] };
                result.Headers.Add(key, value);
            }

            return result;
        }

        #endregion
    }
}

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9