私はMSASP.NETWebAPIクライアントライブラリHttpClient
を使用しProgressMessageHandler
ています。
私はこれをコンソールアプリケーションで問題なくいじくり回しましたが、WinFormアプリでは、「投稿」タスクがまたはのいずれかに固執するだけです。.Wait()
.Result
以下は、私の非常に単純なテストアプリケーションの完全なリストです。ボタン1は正常に機能し、ボタン2はへの呼び出しで毎回フリーズしpostTask.Result
ます。なんで?
4.0または4.5をターゲットにしても違いはありません。コンソールアプリケーションの同じコードには問題はありません。
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Handlers;
using System.Windows.Forms;
namespace WindowsFormsApplication13
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private ProgressMessageHandler _progressHandler = new ProgressMessageHandler();
private const string SERVICE_URL = "http://www.google.com.au";
private HttpClient GetClient(bool includeProgressHandler = false)
{
var handlers = new List<DelegatingHandler>();
if (includeProgressHandler)
{
handlers.Add(_progressHandler);
}
var client = HttpClientFactory.Create(handlers.ToArray());
client.BaseAddress = new Uri(SERVICE_URL);
return client;
}
private void PostUsingClient(HttpClient client)
{
var postTask = client.PostAsJsonAsync("test", new
{
Foo = "Bar"
});
var postResult = postTask.Result;
MessageBox.Show("OK");
}
private void button1_Click(object sender, EventArgs e)
{
using (var client = GetClient())
{
PostUsingClient(client);
}
}
private void button2_Click(object sender, EventArgs e)
{
using (var client = GetClient(true))
{
PostUsingClient(client);
}
}
}
}
アップデート
OK、これが私の問題のようです。.NET 4.5の場合、明らかな解決策は、@ StephenClearyが示唆しているように、非同期/待機パターンをPostAsJsonAsync
呼び出しからボタンクリックハンドラーまで浸透させることです。このようなもの:
private Task<HttpResponseMessage> PostUsingClient(HttpClient client)
{
return client.PostAsJsonAsync("test", new
{
Foo = "Bar"
});
}
private async void button2_Click(object sender, EventArgs e)
{
var client = GetClient(true);
var response = await PostUsingClient(client);
}
今私の問題は、.NET 4.0で同等のソリューションを取得することです(もちろん、レガシーの理由で)。近い近似は、ボタンクリックハンドラーで継続を使用することです。問題は(これもレガシーの理由で)、非同期が戻るまでボタンクリックハンドラーをブロックすることです。4.0互換のyield
演算子を使用していくつかの創造的な解決策を見つけましたが、それらは少し厄介な感じがします。代わりに、私が考案できる最も簡単な代替案は次のとおりです。
private void button2_Click(object sender, EventArgs e)
{
var result = Task.Run(() => { return PostUsingClient(client); }).Result;
}
これが最もパフォーマンスの高い実装であるとは想像できませんが、それでも率直に言って不器用な感じがします。もっと上手くできますか?