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

##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

###使い方


```csharp: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](https://github.com/k--kato/HttpUtility)

##HttpUtilityサンプルアプリ

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

![BookMantion.png](https://qiita-image-store.s3.amazonaws.com/0/67778/19192997-3c6c-7898-1545-28a6dfa09978.png)

###機能

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

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

###ソースコード
　GitHubに掲載しました。

　‡GitHub, "BookMansion," [https://github.com/k--kato/BookMantion/](https://github.com/k--kato/BookMantion/)


##付録（HttpUtilityソースコード一部）


```csharp: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
    }
}

```