WinRT HTTP ClientのUtility化
WinRTのasync/await(非同期)で,HTTP Get/Postリクエストを発行するコードは紋切り型ですので,Utility化したクラスを作ってみました。
HttpUtilityの機能について
HttpUtilityの機能は6個です。
- async/awaitの非同期型
- Proxy認証対応
- レスポンスのシリアライズ化が可能(Object<->JSON変換)
- HTTPレスポンスで自動デコード
- ネットワークの接続状態を自動確認してリクエスト発行
- 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で表示します。
機能
サンプルアプリ画面(XAML)は,Windowsストアアプリ開発の基本的な機能を搭載していますので,ぜひ参考にしてみてください。
- レスポンシブデザイン (解像度変更・画面回転に強い)
- Googleサジェスト(予測変換)に対応
- 簡単な自動テストコードがある
- ソート
- 検索履歴
- ポップアップメニュー
- 設定コントラクト
- 共有コントラクト
ソースコード
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
}
}