スポンサーリンク

ASP.NET Web API クライアント編

サーバー編に続き、クライアント側についてもWCF Web APIの場合と同様にコンソールアプリケーションでクライアントライブラリの使用方法を見ていきます。

全体的な話

WCF Web APIではREST API向けのクライアントライブラリが用意されていましたが、ASP.NET APIでも同様にクライアントライブラリが用意されており、基本的にHttpClientクラスの各メソッドを通してこのライブラリを使用します。

MSDNライブラリ HttpClientクラス:
http://msdn.microsoft.com/ja-jp/library/system.net.http.httpclient(v=vs.110).aspx

HttpClientクラスのHTTPリクエストを実行する各メソッドが特徴的なのは、それらがすべて非同期な点です。ですのでGUIで使用する場合には特にこれらが別スレッドで動作すると意識してコードを書く必要があるでしょう。

ライブラリの追加

必要なライブラリを追加済ます。Web APIのクライアントに必要ライブラリは基本的にASP.NET MVC 4に含まれていますが、依存関係もそれなりにあるので、NuGetを使用した方が楽です。

GUIを使用する場合には下図のように”Microsoft ASP.NET Web API Client Libraries”を選択します。

パッケージマネージャのコンソールからインストールする場合には以下のようにインストールします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
PM> Install-Package Microsoft<span class="hljs-selector-class">.AspNet</span><span class="hljs-selector-class">.WebApi</span><span class="hljs-selector-class">.Client</span>
PM> Install-Package Microsoft<span class="hljs-selector-class">.AspNet</span><span class="hljs-selector-class">.WebApi</span><span class="hljs-selector-class">.Client</span>
PM> Install-Package Microsoft.AspNet.WebApi.Client

using句の追加

Program.csを開いて以下のコードを追加します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">System</span><span class="hljs-selector-class">.Net</span><span class="hljs-selector-class">.Http</span>;
<span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">System</span><span class="hljs-selector-class">.Net</span><span class="hljs-selector-class">.Http</span><span class="hljs-selector-class">.Headers</span>;
<span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">System</span><span class="hljs-selector-class">.Net</span><span class="hljs-selector-class">.Http</span><span class="hljs-selector-class">.Formatting</span>;
<span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">System</span><span class="hljs-selector-class">.Net</span><span class="hljs-selector-class">.Http</span>; <span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">System</span><span class="hljs-selector-class">.Net</span><span class="hljs-selector-class">.Http</span><span class="hljs-selector-class">.Headers</span>; <span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">System</span><span class="hljs-selector-class">.Net</span><span class="hljs-selector-class">.Http</span><span class="hljs-selector-class">.Formatting</span>;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;

データクラスの追加

クライアントサイドで使用するためのデータクラスを追加します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<span class="hljs-comment">//ヒーローのクラスを作成</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Hero</span>
{
<span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
<span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
<span class="hljs-comment">//ヒーローのクラスを作成</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Hero</span> { <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } }
//ヒーローのクラスを作成
public class Hero
{
    public int Id { get; set; }
    public string Name { get; set; }
}

データ格納用のクラスのフィールド名と型はJSONと同じ名前、データ変更可能な型にしておく必要があります。JSONは数値に関してJavaScriptの仕様通り整数、浮動小数点を区別しないので、仕様を良く確認しましょう。

HTTP Getリクエスト

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<span class="hljs-comment">//Getコマンドの実行</span>
static async void <span class="hljs-constructor">ListAllHeroes()</span> {
<span class="hljs-comment">//HttpClientのインスタンスを作成する。</span>
var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>;
<span class="hljs-comment">//↓ ASP.NET Web APIのライブラリではHTTPヘッダでJSONの指定がいらない</span>
<span class="hljs-comment">//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));</span>
<span class="hljs-comment">//GETコマンドを非同期で実行する。</span>
HttpResponseMessage response = await client.<span class="hljs-constructor">GetAsync(<span class="hljs-string">"http://localhost:35833/api/heroes"</span>)</span>;
<span class="hljs-keyword">if</span> (response.IsSuccessStatusCode) {
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"--Get Result--"</span>)</span>;
<span class="hljs-comment">//コンテンツの取得を非同期で実行</span>
var heroes = await response.Content.ReadAsAsync<<span class="hljs-built_in">list</span>><span class="hljs-literal">()</span>;
foreach (var hero <span class="hljs-keyword">in</span> heroes) {
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"{0}\t: {1}"</span>, <span class="hljs-params">hero</span>.Id, <span class="hljs-params">hero</span>.Name)</span>;
}
id = heroes.<span class="hljs-constructor">OrderByDescending(<span class="hljs-params">h</span> => <span class="hljs-params">h</span>.Id)</span>.<span class="hljs-constructor">First()</span>.Id;
}
client.<span class="hljs-constructor">Dispose()</span>;
}</<span class="hljs-built_in">list</span>
<span class="hljs-comment">//Getコマンドの実行</span> static async void <span class="hljs-constructor">ListAllHeroes()</span> { <span class="hljs-comment">//HttpClientのインスタンスを作成する。</span> var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>; <span class="hljs-comment">//↓ ASP.NET Web APIのライブラリではHTTPヘッダでJSONの指定がいらない</span> <span class="hljs-comment">//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));</span> <span class="hljs-comment">//GETコマンドを非同期で実行する。</span> HttpResponseMessage response = await client.<span class="hljs-constructor">GetAsync(<span class="hljs-string">"http://localhost:35833/api/heroes"</span>)</span>; <span class="hljs-keyword">if</span> (response.IsSuccessStatusCode) { Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"--Get Result--"</span>)</span>; <span class="hljs-comment">//コンテンツの取得を非同期で実行</span> var heroes = await response.Content.ReadAsAsync<<span class="hljs-built_in">list</span>><span class="hljs-literal">()</span>; foreach (var hero <span class="hljs-keyword">in</span> heroes) { Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"{0}\t: {1}"</span>, <span class="hljs-params">hero</span>.Id, <span class="hljs-params">hero</span>.Name)</span>; } id = heroes.<span class="hljs-constructor">OrderByDescending(<span class="hljs-params">h</span> => <span class="hljs-params">h</span>.Id)</span>.<span class="hljs-constructor">First()</span>.Id; } client.<span class="hljs-constructor">Dispose()</span>; }</<span class="hljs-built_in">list</span>
//Getコマンドの実行
static async void ListAllHeroes() {
    //HttpClientのインスタンスを作成する。
    var client = new HttpClient();
    //↓ ASP.NET Web APIのライブラリではHTTPヘッダでJSONの指定がいらない
    //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    //GETコマンドを非同期で実行する。
    HttpResponseMessage response = await client.GetAsync("http://localhost:35833/api/heroes");
    if (response.IsSuccessStatusCode) {
        Console.WriteLine("--Get Result--");
        //コンテンツの取得を非同期で実行
        var heroes = await response.Content.ReadAsAsync<list>();
        foreach (var hero in heroes) {
            Console.WriteLine("{0}\t: {1}", hero.Id, hero.Name);
        }
        id = heroes.OrderByDescending(h => h.Id).First().Id;
    }
    client.Dispose();
}</list

ヒーローのリストをサービスから取得して、コンソールに表示させます。

HttpClientクラスのGetAsyncメソッドがGetリクエストを行うメソッドで、非同期で実行されます。(つまりTaskが返されます)

WCF Web APIからの違いは実際にほとんどありません。しかし、C# 5.0のasyc/awaitによってコードがだいぶすっきりして、手続き言語的に見やすいコードになっていますいます。

HTTP POSTリクエスト

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<span class="hljs-comment">//POSTコマンドの実行</span>
static async void <span class="hljs-constructor">AddHero()</span> {
var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>;
<span class="hljs-built_in">string</span> name = <span class="hljs-string">"仮面ライダーアギト"</span>;
<span class="hljs-comment">//POSTコマンドをJSONを指定して非同期で実行</span>
HttpResponseMessage response = await client.<span class="hljs-constructor">PostAsJsonAsync(<span class="hljs-string">"http://localhost:35833/api/heroes"</span>, <span class="hljs-params">name</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"--POST resut--"</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"Status: {0}"</span>, (<span class="hljs-params">int</span>)</span>response.StatusCode);
<span class="hljs-keyword">if</span> (response.IsSuccessStatusCode) {
<span class="hljs-built_in">string</span> m = await response.Content.<span class="hljs-constructor">ReadAsStringAsync()</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-params">m</span>)</span>;
}
client.<span class="hljs-constructor">Dispose()</span>;
}
<span class="hljs-comment">//POSTコマンドの実行</span> static async void <span class="hljs-constructor">AddHero()</span> { var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>; <span class="hljs-built_in">string</span> name = <span class="hljs-string">"仮面ライダーアギト"</span>; <span class="hljs-comment">//POSTコマンドをJSONを指定して非同期で実行</span> HttpResponseMessage response = await client.<span class="hljs-constructor">PostAsJsonAsync(<span class="hljs-string">"http://localhost:35833/api/heroes"</span>, <span class="hljs-params">name</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"--POST resut--"</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"Status: {0}"</span>, (<span class="hljs-params">int</span>)</span>response.StatusCode); <span class="hljs-keyword">if</span> (response.IsSuccessStatusCode) { <span class="hljs-built_in">string</span> m = await response.Content.<span class="hljs-constructor">ReadAsStringAsync()</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-params">m</span>)</span>; } client.<span class="hljs-constructor">Dispose()</span>; }
//POSTコマンドの実行
static async void AddHero() {
    var client = new HttpClient();
    string name = "仮面ライダーアギト";
    //POSTコマンドをJSONを指定して非同期で実行
    HttpResponseMessage response = await client.PostAsJsonAsync("http://localhost:35833/api/heroes", name);
    Console.WriteLine("--POST resut--");
    Console.WriteLine("Status: {0}", (int)response.StatusCode);
    if (response.IsSuccessStatusCode) {
        string m = await response.Content.ReadAsStringAsync();
        Console.WriteLine(m);
    }
    client.Dispose();
}

サービスにヒーローを追加し、応答のステータスコードと結果の内容をコンソールに表示させます。

6行目にあるHttpClietクラスのPostAsJsonAsync(T)メソッドでPOSTしています。このメソッドはJSONでPOSTするようにヘッダを調整し、データをJSONデシリアライズします。

HTTP DELETEリクエスト

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<span class="hljs-comment">//DELETEコマンドの実行</span>
static async void <span class="hljs-constructor">DeleteHero(<span class="hljs-params">int</span> <span class="hljs-params">id</span>)</span> {
var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>;
<span class="hljs-comment">//DELETEコマンドを非同期で実行</span>
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"== Delete Hero ID : {0} =="</span>, <span class="hljs-params">id</span>)</span>;
var url = <span class="hljs-built_in">string</span>.<span class="hljs-constructor">Format(<span class="hljs-string">"http://localhost:35833/api/heroes?id={0}"</span>, <span class="hljs-params">id</span>)</span>;
var response = await client.<span class="hljs-constructor">DeleteAsync(<span class="hljs-params">url</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"--DELETE Result Status Code--"</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"Status: {0}"</span>, (<span class="hljs-params">int</span>)</span>response.StatusCode);
client.<span class="hljs-constructor">Dispose()</span>;
}
<span class="hljs-comment">//DELETEコマンドの実行</span> static async void <span class="hljs-constructor">DeleteHero(<span class="hljs-params">int</span> <span class="hljs-params">id</span>)</span> { var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>; <span class="hljs-comment">//DELETEコマンドを非同期で実行</span> Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"== Delete Hero ID : {0} =="</span>, <span class="hljs-params">id</span>)</span>; var url = <span class="hljs-built_in">string</span>.<span class="hljs-constructor">Format(<span class="hljs-string">"http://localhost:35833/api/heroes?id={0}"</span>, <span class="hljs-params">id</span>)</span>; var response = await client.<span class="hljs-constructor">DeleteAsync(<span class="hljs-params">url</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"--DELETE Result Status Code--"</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"Status: {0}"</span>, (<span class="hljs-params">int</span>)</span>response.StatusCode); client.<span class="hljs-constructor">Dispose()</span>; }
//DELETEコマンドの実行
static async void DeleteHero(int id) {
    var client = new HttpClient();
    //DELETEコマンドを非同期で実行
    Console.WriteLine("== Delete Hero ID : {0} ==", id);
    var url = string.Format("http://localhost:35833/api/heroes?id={0}", id);
    var response = await client.DeleteAsync(url);
    Console.WriteLine("--DELETE Result Status Code--");
    Console.WriteLine("Status: {0}", (int)response.StatusCode);
    client.Dispose();
}

引数idで指定されたヒーローを削除します。

HttpClientクラスのDeleteAsyncメソッドがDELETEを発行します。

HTTP PUTリクエスト

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<span class="hljs-comment">//PUTコマンドの実行</span>
static async void <span class="hljs-constructor">UpdateHero()</span> {
<span class="hljs-built_in">string</span> url = <span class="hljs-string">"http://localhost:35833/api/heroes?id=2"</span>;
<span class="hljs-built_in">string</span> name = <span class="hljs-string">"モロボシダン"</span>;
var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>;
<span class="hljs-comment">//PUTコマンドをJSONを指定して非同期で実行</span>
var response = await client.<span class="hljs-constructor">PutAsJsonAsync(<span class="hljs-params">url</span>, <span class="hljs-params">name</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"-- PUT Result Status Code --"</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"Status: {0}"</span>, (<span class="hljs-params">int</span>)</span>response.StatusCode);
<span class="hljs-keyword">if</span> (response.IsSuccessStatusCode) {
var content = await response.Content.<span class="hljs-constructor">ReadAsStringAsync()</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"-- PUT result --"</span>)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-params">content</span>)</span>;
}
client.<span class="hljs-constructor">Dispose()</span>;
}
<span class="hljs-comment">//PUTコマンドの実行</span> static async void <span class="hljs-constructor">UpdateHero()</span> { <span class="hljs-built_in">string</span> url = <span class="hljs-string">"http://localhost:35833/api/heroes?id=2"</span>; <span class="hljs-built_in">string</span> name = <span class="hljs-string">"モロボシダン"</span>; var client = <span class="hljs-keyword">new</span> <span class="hljs-constructor">HttpClient()</span>; <span class="hljs-comment">//PUTコマンドをJSONを指定して非同期で実行</span> var response = await client.<span class="hljs-constructor">PutAsJsonAsync(<span class="hljs-params">url</span>, <span class="hljs-params">name</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"-- PUT Result Status Code --"</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"Status: {0}"</span>, (<span class="hljs-params">int</span>)</span>response.StatusCode); <span class="hljs-keyword">if</span> (response.IsSuccessStatusCode) { var content = await response.Content.<span class="hljs-constructor">ReadAsStringAsync()</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"-- PUT result --"</span>)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-params">content</span>)</span>; } client.<span class="hljs-constructor">Dispose()</span>; }
//PUTコマンドの実行
static async void UpdateHero() {
    string url = "http://localhost:35833/api/heroes?id=2";
    string name = "モロボシダン";
    var client = new HttpClient();
    //PUTコマンドをJSONを指定して非同期で実行
    var response = await client.PutAsJsonAsync(url, name);
    Console.WriteLine("-- PUT Result Status Code --");
    Console.WriteLine("Status: {0}", (int)response.StatusCode);
    if (response.IsSuccessStatusCode) {
        var content = await response.Content.ReadAsStringAsync();
        Console.WriteLine("-- PUT result --");
        Console.WriteLine(content);
    }
    client.Dispose();
}

Idが2のヒーローの名前を変更しています。

7行目のPutAsJsonAsyncメソッドでPUTを発行しています。これも非同期です。

まとめ

C# 5.0の非同期関連機能の向上でコードがだいぶすっきりしています。手続き的な書き方に慣れている方にとってはこちらの方が見やすいと感じるでしょう。
クライアントに関してはWCF Web APIからの大きな違いはありませんが、必ずしもそのままというわけでも無いので、良くドキュメントを読んでおきましょう。また、JSON/XMLのシリアリアライズとヘッダ設定を行ってくれるPUT/POST用のメソッドが用意されています。

まずは製品版のクラスライブラリに入ってきたことが一番大きいと思いますので、いろいろと縛りがある人でも使用しやすくなってきたと思いますので、皆さんも是非使ってみて下さい。

コードの公開

サーバー編と同じくGitHubで全体のコードを公開しています。

GitHub - ishisaka/superhero2: SuperHero2
SuperHero2. Contribute to ishisaka/superhero2 development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました