質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

Q&A

解決済

2回答

19966閲覧

HttpClientでPostでhttpサーバーに文字を送信して、結果のJsonを取得したい

TrainRain

総合スコア20

C#

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

0グッド

0クリップ

投稿2018/12/03 01:50

こんにちは。

前提・実現したいこと

Windows10を使ってVisual Studo 2017でUWPアプリケーションのプロジェクトを作っています。
Postでhttpサーバーに文字を送信して、結果のJsonを取得したいです。

UWPにはWebClientがないので、もともとWebClientとHttpUtilityを使っていたのをHttpClientに変更したいです。

argsはキーのペアで、
name, "白鷺",
language, "japanese",
kind, "bird"
のようなものです。

urlはhttpサーバーのurlです。

resultはjsonです。

発生している問題・エラーメッセージ

C#

1 client.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.5"); 2  client.DefaultRequestHeaders.Add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

あたりで、接続に失敗します。
HttpClientを使うのが初めてで、なにを渡したらよいかわからずにおります。

該当のソースコード

もとのコードです。

C#

1public static string GetJsonResult(Dictionary<string, string> args, string url) 2{ 3 string data = CreateQuerystring(args); 4 string result = GetHttpResponse(url, data); 5} 6 7public static string CreateQuerystring(Dictionary<string, string> args) 8{ 9 StringBuilder sb = new StringBuilder(); 10 foreach (string name in args.Keys) 11 { 12 sb.Append(HttpUtility.UrlEncode(name)); 13 sb.Append("="); 14 15 sb.Append(HttpUtility.UrlEncode(args[name])); 16 sb.Append("&"); 17 } 18 return sb.ToString(0, Math.Max(sb.Length - 1, 0)); 19} 20 21public static string GetHttpResponse(string url, string data) 22{ 23 byte[] rawData = client.UploadData(url, Encoding.UTF8.GetBytes(data)); 24 return Encoding.UTF8.GetString(rawData); 25}

試したこと

public static string GetHttpResponse(string url, string data) { HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.5");   client.DefaultRequestHeaders.Add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); var stringContent = new StringContent(data, System.Text.Encoding.UTF8); var message = client.PostAsync(url, stringContent); return message.Result.Content.ToString(); } public static string CreateQuerystring(Dictionary<string, string> args) { StringBuilder sb = new StringBuilder(); foreach (string name in args.Keys) { sb.Append(Uri.EscapeDataString(name)); sb.Append("="); sb.Append(Uri.EscapeDataString(args[name])); sb.Append("&"); } return sb.ToString(0, Math.Max(sb.Length - 1, 0)); }

求める回答

Q1)HttpClientのPostのコード。GetHttpResponse(string url, string data)のMethod
Q2)client.DefaultRequestHeadersを全部コメントアウトするとつながるが、そのとき結果はmessageのどこに入っているか。
Q3)そもそもはいっていないのか?

補足情報(FW/ツールのバージョンなど)

Intel Pentium(R) CPU 4415 Y 1.60GHz RAM 8GB Windows10Pro 64bit 1803 17134.345 Microsoft Visual Studio Community 2017 Version 15.8.5 VisualStudio.15.Release/15.8.5+28010.2036 Microsoft .NET Framework Version 4.7.03056 インストールされているバージョン:Community

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

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

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

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

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

guest

回答2

0

Q1)HttpClientのPostのコード。GetHttpResponse(string url, string data)のMethod

以下の記事のコードが参考になりませんか? WCF と書いてありますが Web サーバーに HttpClient を使って POST 要求をかけ、JSON 文字列を応答として受け取るところは質問者さんのケースと同じです。

HttpClient で WCF サービスを呼出
http://surferonwww.info/BlogEngine/post/2018/02/24/request-wcf-service-using-httpclient.aspx

応答として受け取った JSON 文字列を C# のオブジェクトにデシリアライズしないと処置できないと思いますが、そのあたりのコードも書いてあります。

質問者さんのケースでは、POST するのは JSON 文字列ではなくて application/x-www-form-urlencoded 形式のようで、その文字列を CreateQuerystring メソッドで取得するのだろうと思いますが、そうであれば紹介した記事のコードを以下のように変更すればよさそうです。

string postData = CreateQuerystring(args); request.Content = new StringContent(postData, Encoding.UTF8, "application/x-www-form-urlencoded");

Q2)client.DefaultRequestHeadersを全部コメントアウトするとつながるが、そのとき結果はmessageのどこに入っているか。

Fiddler を使って要求・応答をキャプチャして調べてください。その中にヒントが含まれているはずです。今の情報で言えるのはそれぐらいしかないです。

【追伸】

下の 2018/12/03 13:19 の私のコメントで Fiddler で「どういう情報が得られるかは、後で回答欄に書いておきます」と書きましたが、それを以下に書きます。

以下の画像は上の回答で紹介した記事「HttpClient で WCF サービスを呼出」のコードを実行した際の要求・応答を Fiddler でキャプチャしたものです。期待通り要求がサーバーに送信され、サーバーから応答が返ってきていることが分かります。Fiddler 無しでは要求が出ているか否かさえも分かりません。まして、応答が返ってきているか、それは期待通りかなんてことは分かりません。

イメージ説明

質問者さんの Q2, Q3 の疑問「結果はmessageのどこに入っているか」「そもそもはいっていないのか?」も Text を見るなどすればすぐに分かります。

イメージ説明

なので、Fiddler なしで HTTP 通信を行うアプリの開発は無理と言っても過言ではないと思います。

(注)クライアントにブラウザを使う場合と違って、デスクトップアプリなどからですと localhost はキャプチャできないので注意してください。

投稿2018/12/03 03:41

編集2018/12/03 04:40
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

TrainRain

2018/12/03 04:07

丁寧にありがとうございます。 Fiddlerというのはなんですか? ふだんはVisual Studioのデバッグで、変数の中を見ています。 messageには見当たらなかったのです。Fiddlerをつかうともっと情報を得られるのでしょうか。
guest

0

ベストアンサー

こんにちは。

「接続に失敗する」というのは状況がよくわかりませんが、
PostAsyncの結果から中身を取り出すには、Contentに対してReadAsStringAsyncを使います。

csharp

1 var message = client.PostAsync(url, stringContent); 2 return message.Result.Content.ReadAsStringAsync().Result;

接続ができているなら、上のやり方で結果を取り出すことができると思います。


本来HttpClientは非同期APIなので、基本的には非同期コンテキストで走らせるものです。

csharp

1 var response = await client.PostAsync(url, stringContent); 2 return await response.Content.ReadAsStringAsync();

正しく扱うには非同期処理の基礎を学ぶ必要があるため、習得していないうちは同期記法でもよいです(HttpClientの場合は例外的に。大半の非同期APIは同期で書こうとするとほぼデッドロックするので非常に危険です。)
UWP以降になると非同期処理の習得がほぼ必須なので、そちらの学習を優先したほうが良いです。

投稿2018/12/03 02:20

tamoto

総合スコア4103

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

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

TrainRain

2018/12/03 02:56

早速のご返答ありがとうございます。検証します。
TrainRain

2018/12/04 01:14

ありがとうございました。 そのMethodはうまくできたようなのですが、ご心配頂いていた通り、非同期処理で新たに課題が発生しました。 var response = GetHttpResponse(baseUrl, data).ToString(); var json = JArray.Parse(response);//<-このresponseが空のまま実行してしまう。 return json; これを修正するには、 var response = await GetHttpResponse(baseUrl, data).ToString(); var json = await JArray.Parse(response); と両方にawaitすればよいのでしょうか? あるいはJArray.Parse(response);をGetHttpResponseで実行して、Parseずみのjsonをawaitで戻せばよいのか。いずれにしても非同期にするために、あちこちだいぶ手を入れないとダメっぽくて…。
tamoto

2018/12/04 01:24

根本的に非同期が理解できていないまま非同期フローを書くのはおそらく不可能です。 現状のGetHttpResponseの実装がどうなっているのかがわからないとコメントへの回答は難しいです。 仮にそのGetHttpResponseの中身が本回答の1つ目で書いた同期処理版であるとすれば、GetHttpResponseの型はstringなのでToString()は不要なはずです。そして、responseが空であるというのは、HTTP通信のレスポンス自体が空ということになります。 もしGetHttpResponseを非同期メソッドにしようとしてTaskを返していた場合は、それをToString()しても当然正しい結果は得られません。
TrainRain

2018/12/04 01:35

おっしゃるとおりです。ありがとうございました。この質問はとりあえずここで完了にします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問