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

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

ただいまの
回答率

90.49%

  • C#

    7413questions

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

  • HTTP

    559questions

    HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

  • HttpWebRequest

    54questions

    HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

C#でHTTP通信を行う方法(HttpClientを用いる場合)

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 11K+

alths122

score 10

 目的

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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

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

上記のコードで、コンパイルエラー、実行エラーともに発生せず、期待通りの動作ができることを確認しました。

ご参考になれば。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 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

    ビルドエラーが発生する原因はわかりませんが、こちらで動作検証してみましたので、そのソースコードを追記しました。ご自身の実際のコードと見比べてみてください。

    キャンセル

+1

自己解決しました。
以下サイトのスライド 29~35ページの内容と同じ問題でした。

HttpClient詳解、或いは非同期の落とし穴について
http://www.slideshare.net/neuecc/httpclient

awaitにより待機のデッドロックが発生しておりました。
今回は、await client.GetStringAsync(uri)
await client.GetStringAsync(uri).ConfigureAwait(false)に変更することで解決しました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

関連した質問

同じタグがついた質問を見る

  • C#

    7413questions

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

  • HTTP

    559questions

    HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

  • HttpWebRequest

    54questions

    HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。