C#でHTTP通信を行う方法(HttpClientを用いる場合)
解決済
回答 2
投稿
- 評価
- クリップ 1
- VIEW 23K+
目的
C#でHTTP通信を行い、その結果を取得したいと思っています。
(最終的にはWeb APIを叩くことが目的です)
資料となるサイトを参考にコードを書いてみたのですが応答が返らず、対処方法が分からないので教えていただきたいです。
実装
まっさらなC#/Formsアプリに、ボタンを一つだけ用意します。
ボタンを押すとWebアクセスを試みるだけのプログラムです。
[フォーム側(ボタンを押すとアクセス)]
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
}
private void btnRequest_Click(object sender, EventArgs e)
{
Uri uri = new Uri("http://www.google.com");
// ここでwebアクセスを行う
Task<string> webTask = WebConn.GetApiAsync(uri);
string result = webTask.Result;
Console.WriteLine(result);
}
}
[アクセス処理(WebConn)]
public class WebConn
{
public static async Task<string> GetApiAsync(Uri uri)
{
using (HttpClient client = new HttpClient())
{
// ヘッダ情報設定
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko");
client.DefaultRequestHeaders.Add("Accept-Language", "ja-JP");
client.Timeout = TimeSpan.FromSeconds(5.0);
try
{
// 実際のアクセス処理はここだけ
string res = await client.GetStringAsync(uri);
// ここに辿りつけない
return res;
} catch(HttpRequestException e)
{
// 例外処理(省略)
}
return null;
}
}
}
発生している問題
上記のコードを実行しフォームに用意したボタンを押したところ、ウィンドウが操作を受け付けない状態になります。
具体的には、上記コード(アクセス処理)の
string res = await client.GetStringAsync(uri);
を実行した後、次の return res;
に辿り着きません。
また、実行時に例外が発生することもありません。
参考資料
@ITの記事
http://www.atmarkit.co.jp/ait/articles/1501/06/news086.html
に掲載されているコードを、ほぼ流用しています。
その他
C#を用いて通信を行うのは初めてです。
もしHttpClient使うより良い方法があれば教えてください。
(ところでteratailでは、C#のコードはシンタックスハイライトされないのでしょうか…?)
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
}
// await するために async 宣言を追加
private async void btnRequest_Click(object sender, EventArgs e)
{
Uri uri = new Uri("http://www.google.com");
// ここでwebアクセスを行う
// 非同期にするために await 宣言を追加
Task<string> webTask = await WebConn.GetApiAsync(uri);
string result = webTask.Result;
Console.WriteLine(result);
}
}
このようにしたら動きそうな予感が。
(参考)Async および Await を使用した非同期プログラミング (C# および Visual Basic)
(追記)動作検証済みサンプルコード
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net.Http;
namespace AsyncTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
Debug.WriteLine("Clicked!");
string s = await WebConn.GetApiAsync();
Debug.WriteLine("check 3, len = " + s.Length);
}
}
public class WebConn
{
public static async Task<string> GetApiAsync()
{
using (HttpClient client = new HttpClient())
{
Debug.WriteLine("check 1");
string urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
Debug.WriteLine("check 2");
return urlContents;
}
}
}
}
Form1は、空のWindowsフォームに、ボタンを一つ貼り付け打だけのものです。
OS:Windows 10 (10.0.10586)
VS: Visual Studio 2015
.NetFramework: 4.5
上記のコードで、コンパイルエラー、実行エラーともに発生せず、期待通りの動作ができることを確認しました。
ご参考になれば。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
自己解決しました。
以下サイトのスライド 29~35ページの内容と同じ問題でした。
HttpClient詳解、或いは非同期の落とし穴について
http://www.slideshare.net/neuecc/httpclient
awaitにより待機のデッドロックが発生しておりました。
今回は、await client.GetStringAsync(uri)
を
await client.GetStringAsync(uri).ConfigureAwait(false)
に変更することで解決しました。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/05/03 23:06
実のところ、この方法も下で挙げたスライドに書いてあったのですが、
この方法だと何故か `await WebConn.GetApiAsync(uri)` の箇所で
`型 'string' を 'System.Threading.Tasks.Task<string>' に暗黙的に変換できません`と言われてしまいます。
どう見ても`WebConn.GetApiAsync()`はstringを返す実装ではないと思うのですが、awaitを付けると、暗黙的にstringを返すような処理に変更でもされるのでしょうか…?
2016/05/04 13:24