先の記事「HttpWebRequest で WCF サービスを呼出」では、JSON 文字列をデータとしてやり取りする WCF サービスのメソッドを HttpWebRequest / HttpWebResponse を利用して呼び出して JSON 文字列のデータを取得し、それを逆シリアル化して C# のオブジェクトに変換する方法を書きました。
HttpWebRequest / HttpWebResponse に代えて HttpClient を利用し、同じ WCF サービスのメソッドを呼び出してデータを取得するサンプルを書きます。 (呼び出し先の WCF サービスは「WCF と jQuery AJAX」を参照)
参考にしたのは Call a Web API From a .NET Client (C#) という記事ですので合わせて見ていただくと良いと思います。
まず、先の HttpWebRequest / HttpWebResponse を利用した記事と同様に、以下のクラス / データコントラクト定義を行います。
[DataContract]
public class RootObject
{
// GetCarsByDoorsResult は WCF サービスメソッドに付与した
// BodyStyle = WebMessageBodyStyle.WrappedRequest による
// ラップの名前(ラップするのはセキュリティ対策)
[DataMember]
public List<Car> GetCarsByDoorsResult { get; set; }
}
[DataContract]
public class Car
{
[DataMember]
public string Make { get; set; }
[DataMember]
public string Model { get; set; }
[DataMember]
public int Year { get; set; }
[DataMember]
public int Doors { get; set; }
[DataMember]
public string Colour { get; set; }
[DataMember]
public float Price { get; set; }
}
参考にした Microsoft の記事ではデシリアライズに HttpContentExtensions.ReadAsAsync<T> メソッド (HttpContent) を使っていますが、今回の例のような入れ子になったオブジェクトはデシリアライズできないようです。
なので、先の記事と同様、DataContractJsonSerializer クラスを利用して応答ストリームに含まれる JSON 文字列を C# のオブジェクトにデシリアライズすることにしました。
HttpClient.SendAsync メソッドを利用して、JSON 文字列を WCF サービスの GetCarsByDoors(int doors) メソッドに POST 送信します。以下のコードの例では 5 ドア車を要求しています。
応答の HttpContent が HttpClient.SendAsync メソッドの戻り値として返されますので、DataContractJsonSerializer クラスを利用して応答ストリームに含まれる JSON 文字列を C# のオブジェクトにデシリアライズします。
詳しくは以下のサンプルコードとそれに付与したコメントを見てください。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading.Tasks;
using System.Net.Http;
using System.IO;
namespace ConsoleAppHttpClientWCF
{
class Program
{
static void Main(string[] args)
{
// GetCarsAsync メソッドの引数で 5 ドアを要求
RootObject rootObject =
GetCarsAsync(5).GetAwaiter().GetResult();
ShowCars(rootObject);
}
static async Task<RootObject> GetCarsAsync(int doors)
{
using (HttpClient httpClient = new HttpClient())
{
string url = "http://.../GetCarsByDoors";
// POST 送信を指定
HttpRequestMessage request =
new HttpRequestMessage(HttpMethod.Post, url);
// POST 送信する JSON 文字列
string postData =
"{\"doors\":" + doors.ToString() + "}";
// Content-Type: application/json; charset=utf-8 が
// 要求ヘッダに必要。それを POST 送信する JSON 文字
// 列と共にここで設定
request.Content = new StringContent(postData,
Encoding.UTF8,
"application/json");
var response = await httpClient.SendAsync(request);
// 応答のコンテンツを Stream として取得
using (Stream responseStream =
await response.Content.ReadAsStreamAsync())
{
// JSON シリアライザの初期化
DataContractJsonSerializer ser =
new DataContractJsonSerializer(typeof(RootObject));
// 応答のコンテンツを逆シリアル化して C# の
// オブジェクトを取得
RootObject rootObject =
(RootObject)ser.ReadObject(responseStream);
return rootObject;
}
}
}
// コンソールに取得結果を書き出すためのヘルパメソッド
static void ShowCars(RootObject rootObject)
{
foreach (Car car in rootObject.GetCarsByDoorsResult)
{
Console.WriteLine("Make:{0}, Model:{1}, Doors:{2}",
car.Make, car.Model, car.Doors);
}
}
}
/*
結果は:
Make:Audi, Model:A4, Doors:5
Make:Ford, Model:Focus, Doors:5
Make:Renault, Model:Laguna, Doors:5
Make:Toyota, Model:Previa, Doors:5
*/
}
DataContractJsonSerializer クラスを利用したシリアル化 / 逆シリアル化については、MSDN ライブラリの記事「方法 : JSON データをシリアル化および逆シリアル化する」が参考になると思います。
なお、本題とは直接関係ないことですが、You're using HttpClient wrong and it is destabilizing your software によると、HttpClient の初期化と Dispose を繰り返すようなことをすると、socket が浪費されるという問題があるそうです。これは覚えておいた方がよさそうです。