かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ストリーミングのAPIにPostでアクセスするとき

HttpClientのPostAsyncだとStreamを全部読み終わるまで帰ってこないみたいです。 そんなAPIって何?っていうとTwitterのこれとかがそうみたいです。

そんなときはPostAsyncじゃなくて、もう一段抽象度の低いSendAsyncメソッドを使ってHttpRequestMessageを組み立ててSendAsyncするといいです。SendAsyncメソッドの引数にHttpCompletionOptionを受け取るものがあって、これの引数をHttpCompletionOption.ResponseHeadersReadに指定すると、BodyじゃなくてHeaderだけ読み取ったら制御を返してくれます。

例えばTwitterにアクセスできるHttpClientがclientという変数であるとして、上のドキュメントの通りtrack=twitterというBodyで送るコードは以下のようになります。

var apiUrl = "https://stream.twitter.com/1.1/statuses/filter.json";
var req = new HttpRequestMessage(HttpMethod.Post, apiUrl);
req.Content = new FormUrlEncodedContent(new Dictionary<string, string> 
{ 
    {"track", "twitter"} 
});
// タイムアウト無制限
client.Timeout = Timeout.InfiniteTimeSpan;
var res = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
Debug.WriteLine(res);
using (var sr = new StreamReader(await res.Content.ReadAsStreamAsync()))
{
    while(!sr.EndOfStream)
    {
        // 何か処理をする
        Debug.WriteLine(await sr.ReadLineAsync());
    }
}