🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

3895閲覧

C#でのHttpリクエストの送信について

moshi

総合スコア90

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2019/11/18 08:19

編集2019/11/19 00:49

前提・実現したいこと

C#でHttpのリクエストを送信し、その戻り値によって処理を分けたいです。

試したこと

HttpClientを使ってみるを参考に少し改良して以下のソースを作成しました。

using System.Net.Http; // ←追加 private static HttpClient client = new HttpClient(); private async Task<string> sendRequest(string url, string json) { // メソッドにPOSTを指定 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url); // 今回はJSONをPOSTしてみる request.Content = new StringContent(json, Encoding.UTF8, "application/json"); // リクエストを送信し、その結果を取得 var response = await client.SendAsync(request); // 取得した結果をstring形式で返す return await response.Content.ReadAsStringAsync(); }
static void Main(string[] args) { string url = "http://******"; // post先 string json = "{\"age\":\"44歳\",\"name\":\"大泉 洋\"}"; // 送信するJSON string responseData = "";   // リクエスト送信して、タスクの返りを待つ sendRequest(url, json).ContinueWith( (task) => { // レスポンスを取得 responseData = task.Result; }); if(responseData.Length == 0){ Console.Write("失敗"); }

この時、自分としては、taskの完了を待ってから

if(responseData.Length == 0){

の判定に進むのかと思ったのですが、デバッガーで進めていくと

if(responseData.Length == 0) ``` を先に見てから

responseData = task.Result;

が設定されているようでした。(この時点ではresponseData には期待した値が入っていますが先にresponseData.Length == 0を通ってしまうためいつも「失敗」が返ってきます。) どうすればよいでしょうか? ### 補足情報(FW/ツールのバージョンなど) C# ### 追記 さらにここからリクエストを送信する場合は以下のようにするのでしょうか? また、見ていたページを参考にただ書いただけなのですが、結果をまって次の処理をするならば同期的に処理をしてもいい気がするのですがどうでしょうか…

string url = "http://******"; // post先
string json = "{"age":"44歳","name":"大泉 洋"}"; // 送信するJSON

string responseData = "";

  // リクエスト送信して、タスクの返りを待つ
sendRequest(url, json).ContinueWith(
(task) =>
{
// レスポンスを取得
responseData = task.Result;
if(responseData.Length == 0){
Console.Write("失敗");
}
url = "http://******/test";
json = "{\test1"":"aa","test2":"bb"}";
string responseData2 = "";
sendRequest(url, json).ContinueWith(
(task2) =>
{
// レスポンスを取得
responseData2 = task2.Result;
});
});

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

下記のタスクはレスポンスが返ってくるまで非同期で待機しています。

C#

1(task) => 2{ 3 // レスポンスを取得 4 responseData = task.Result; 5}

非同期で待機しているということは、sendRequest(url, json).ContinueWith(~)を呼び出した元のスレッドはレスポンスを待たずに処理を続行しますので、大体はレスポンスを受け取る前にif(responseData.Length == 0)の処理が実行されると思います。

レスポンスで受け取った値はそのタスクの中だけで参照するようにしてください。

C#

1  // リクエスト送信して、タスクの返りを待つ 2 sendRequest(url, json).ContinueWith( 3 (task) => 4 { 5 // レスポンスを取得 6 responseData = task.Result; 7 if(responseData.Length == 0){ 8 Console.Write("失敗"); 9 } 10 });

ContinueWithの代わりにawaitを使えばネストを深くさせずに書けます。
awaitMainメソッドで使うには非同期 Mainにする必要があります。
下記コードは環境がないため、イメージで書きました。誤りがあればコメントをお願いします。

C#

1static async Task Main () { 2 string url = "http://******"; // post先 3 string json = "{\"age\":\"44歳\",\"name\":\"大泉 洋\"}"; // 送信するJSON 4 5 // リクエスト送信して、タスクの返りを待つ 6 var responseData = await sendRequest (url, json); 7 if (responseData.Length == 0) { 8 Console.Write ("失敗"); 9 } 10 11 var responseData2 = await sendRequest (url, json); 12}

投稿2019/11/18 08:26

編集2020/02/18 05:11
BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moshi

2019/11/19 00:50

ご回答ありがとうございます。 可能でしたら追記についても教えていただけますでしょうか。
BluOxy

2019/11/21 07:29 編集

> 結果をまって次の処理をするならば同期的に処理をしてもいい気がする GUIアプリの場合はHTTPのレスポンスを待っている間に画面の描画ができなくなります。そこで、画面の描画用のスレッド(メインスレッド)とHTTP通信用のスレッド(ワーカスレッド)で分けられるようasync/awaitを使った非同期処理が実現されています。今回のケースではいらないかもしれません。 > さらにここからリクエストを送信する場合は以下のようにするのでしょうか? その書き方でも動作すると思います。 しかし、非同期Mainを使い、タスクの待機をContinueWithではなくawaitで待つことでネストが深くならずに複数のタスクを呼ぶこともできます。
BluOxy

2019/11/19 02:47

話が前後しましたが、asyncメソッド上でawaitができればどこでsendRequestを呼び出しても構わないです。今回掲示されたコードがたまたまMainメソッドだったので、非同期Mainにしました。
moshi

2019/11/19 02:56

丁寧な回答ありがとうございます。 そういった意味での非同期処理だったのですね。勉強になります。 今回はAPIを呼び出してDBから情報を持ってくるというだけの処理で画面などはないのでBluOxyさんのおっしゃる通り同期的な処理でいい気がしてきました。 書いていただいたソースを実行してみようとしたところエラーが出てしまったのですがsendRequest メソッドの修正が必要でしょうか
BluOxy

2019/11/19 03:02

エラーメッセージはなんでしょうか。 掲示したコードは申し訳ないですが、デバッグをしていないので、可能なら適宜コンパイルエラーは直してもらえますでしょうか。 回答としては「ContinueWithの代わりにawaitを使えばネストを深くさせずに書ける」です。コードはおまけのようなものなので。 誤っている部分はコメント頂ければ随時修正いたします。
Zuishin

2019/11/19 03:08

> var task = await sendRequest (url, json); 非同期コンテキストなので、sendRequest の戻り値が Task<string> であった場合、task の型は string になります。確かめていませんが、多分ここじゃないでしょうか。
BluOxy

2019/11/19 03:14

なるほど、それですね。失礼いたしました。
moshi

2019/11/19 04:46

var responseData = await sendRequest (url, json); を呼び出していた関数の戻り値にasyncを指定していないのが原因でした。 細かくありがとうございました。 Zuishinさんもありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問