web-dev-qa-db-ja.com

非同期HttpWebRequestの応答を取得する

非同期httpwebrequestの応答を取得する簡単な方法があるかどうか疑問に思っています。

私はすでにこの質問を見てきました here しかし、私がやろうとしているのは、応答(通常はjsonまたはxml)を別のメソッドに文字列の形で返すことですそれに応じて。

ここにいくつかのコードがあります:

すべてのパラメータが渡され、メソッドが使用する共有ローカル変数がないため、スレッドセーフであると思うこれらの2つの静的メソッドがここにありますか?

public static void MakeAsyncRequest(string url, string contentType)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.ContentType = contentType;
    request.Method = WebRequestMethods.Http.Get;
    request.Timeout = 20000;
    request.Proxy = null;

    request.BeginGetResponse(new AsyncCallback(ReadCallback), request);
}

private static void ReadCallback(IAsyncResult asyncResult)
{
    HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
    try
    {
        using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult))
        {
            Stream responseStream = response.GetResponseStream();
            using (StreamReader sr = new StreamReader(responseStream))
            {
                //Need to return this response 
                string strContent = sr.ReadToEnd();
            }
       }
       manualResetEvent.Set();
    }
    catch (Exception ex)
    {
        throw ex;
   }
}
18
gdp

問題が返されたコンテンツに到達するのに苦労していると仮定すると、最も簡単な方法は、使用できる場合はasync/awaitを使用することです。 .NET 4.5を使用している場合は、「ネイティブ」に非同期であるため、HttpClientに切り替えるのがさらに良いでしょう。

.NET 4とC#4を使用すると、タスクを使用してこれらをラップし、最終結果にアクセスしやすくすることができます。たとえば、1つのオプションは次のようになります。コンテンツ文字列が利用可能になるまでMainメソッドをブロックしていることに注意してください。ただし、「実際の」シナリオでは、タスクを別の何かに渡すか、別のContinueWithの文字列またはその他の文字列を追加します。

void Main()
{
    var task = MakeAsyncRequest("http://www.google.com", "text/html");
    Console.WriteLine ("Got response of {0}", task.Result);
}

// Define other methods and classes here
public static Task<string> MakeAsyncRequest(string url, string contentType)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.ContentType = contentType;
    request.Method = WebRequestMethods.Http.Get;
    request.Timeout = 20000;
    request.Proxy = null;

    Task<WebResponse> task = Task.Factory.FromAsync(
        request.BeginGetResponse,
        asyncResult => request.EndGetResponse(asyncResult),
        (object)null);

    return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
}

private static string ReadStreamFromResponse(WebResponse response)
{
    using (Stream responseStream = response.GetResponseStream())
    using (StreamReader sr = new StreamReader(responseStream))
    {
        //Need to return this response 
        string strContent = sr.ReadToEnd();
        return strContent;
    }
}
41
James Manning

「.NET 4.5を使用している場合は、「ネイティブ」に非同期であるため、HttpClientに切り替えるのがさらに良いでしょう。」 -ジェームス・マニングによる絶対的な正解。この質問は約2年前に尋ねられました。これで、強力な非同期メソッドを提供する.NET Framework 4.5ができました。 HttpClientを使用します。次のコードを検討してください。

 async Task<string> HttpGetAsync(string URI)
    {
        try
        {
            HttpClient hc = new HttpClient();
            Task<Stream> result = hc.GetStreamAsync(URI);

            Stream vs = await result;
            StreamReader am = new StreamReader(vs);

            return await am.ReadToEndAsync();
        }
        catch (WebException ex)
        {
            switch (ex.Status)
            {
                case WebExceptionStatus.NameResolutionFailure:
                    MessageBox.Show("domain_not_found", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;
                    //Catch other exceptions here
            }
        }
    }

HttpGetAsync()を使用するには、「非同期」でもある新しいメソッドを作成します。 GetWebPage()メソッドで「await」を使用する必要があるため、asyncが必要です。

async void GetWebPage(string URI)
        {
            string html = await HttpGetAsync(URI);
            //Do other operations with html code
        }

WebページのHTMLソースコードを非同期で取得する場合は、GetWebPage( "web-address ...")を呼び出すだけです。ストリーム読み取りでも非同期です。

注:HttpClient .NET framework 4.5を使用する必要があります。また、プロジェクトにSystem.Net.Http参照を追加し、簡単にアクセスできるように「using System.Net.Http」も追加する必要があります。

このアプローチがどのように機能するかについての詳細は、次をご覧ください: http://msdn.Microsoft.com/en-us/library/hh191443(v = vs.110).aspx

非同期の使用: 4.5の非同期:待つ価値

7
mirushaki

非同期になったら、戻ることはできません。そこからは、非同期のコールバックにのみ実際にアクセスできます。あなたはこれの複雑さを増やし、いくつかのスレッド化とウェイトハンドルを行うことができますが、それはかなり苦痛な努力になる可能性があります。

技術的には、結果を待つ必要があるときにスレッドをスリープさせることもできますが、その時点で通常のhttpリクエストを行うこともお勧めしません。

C#5には、メインスレッドへの非同期呼び出しの結果を簡単に取得できるasync/awaitコマンドがあります。

2
Thinking Sites
public static async Task<byte[]> GetBytesAsync(string url) {
    var request = (HttpWebRequest)WebRequest.Create(url);
    using (var response = await request.GetResponseAsync())
    using (var content = new MemoryStream())
    using (var responseStream = response.GetResponseStream()) {
        await responseStream.CopyToAsync(content);
        return content.ToArray();
    }
}

public static async Task<string> GetStringAsync(string url) {
    var bytes = await GetBytesAsync(url);
    return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
0
dragansr