3

UI スレッドをブロックせずに、WinForms アプリケーションで非同期にHttpWebRequest使用しようとしています。HttpWebResonse

方法を説明するこの同様の SO Questionを見ました。ただし、受け入れられた答えが正しい方法であると100%確信しているわけではありません。受け入れられた答えはを使用してBeginGetResponseいます。

MSDNのドキュメントによると:

BeginGetResponse メソッドでは、このメソッドが非同期になる前に、いくつかの同期セットアップ タスク (DNS 解決、プロキシ検出、TCP ソケット接続など) を完了する必要があります。結果として、このメソッドはユーザー インターフェイス (UI) スレッドで呼び出されるべきではありません。これは、通常は数秒かかる場合があるためです。

誰かがこれを行う正しい方法を教えてください。UIスレッドをブロックせずに「適切に」機能させようとしているC#関数を次に示します。

    private IDictionary<string, object> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader)
    {
        var req = (HttpWebRequest)WebRequest.Create(endPoint);
        req.Method = method;
        if (addAuthHeader)
        {
            req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
        }

        if (!string.IsNullOrEmpty(data))
        {
            var utfenc = new UTF8Encoding();
            byte[] buffer = utfenc.GetBytes(data);
            req.ContentLength = buffer.Length;
            req.ContentType = "application/x-www-form-urlencoded";

            using (Stream strm = req.GetRequestStream())
            {
                strm.Write(buffer, 0, buffer.Length);
                strm.Close();
            }
        }

        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException e)
        {
            if (_accessToken == null)
            {
                throw;
            }
            var responseError = (HttpWebResponse)e.Response;
            if (responseError.StatusCode == HttpStatusCode.Unauthorized)
            {
                var stackTrace = new StackTrace();
                var q = stackTrace.GetFrame(1).GetMethod().Name;
                RefreshAccessCode();

                req = (HttpWebRequest)WebRequest.Create(endPoint);
                req.Method = method;
                if (addAuthHeader)
                {
                    req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
                }
                response = (HttpWebResponse)req.GetResponse();
            }
        }

        string jsonResponse = null;

        if (response != null)
            using (Stream stream = response.GetResponseStream())
            {
                if (stream != null)
                {
                    using (var reader = new StreamReader(stream))
                    {
                        jsonResponse = reader.ReadToEnd();
                    }
                }
            }

        return DeserializeResponse(jsonResponse);
    }
4

2 に答える 2

3

あなたが WebRequest 以外のことを受け入れるなら、私はSystem.Net.WebClientのファンです。BeginGetResponse() と EndGetResonse() の代わりに System.Threading.Tasks を使用します。

public async Task<Dictionary<string, object>> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader)
{
    WebClient client = new WebClient();

    if (addAuthHeader)
    {
        client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
    }

    byte[] buffer = null;

    if (!string.IsNullOrEmpty(data))
    {
        var utfenc = new UTF8Encoding();
        buffer = utfenc.GetBytes(data);
    }
    else
    {
        buffer = new byte[0];
    }

    return await client.UploadDataTaskAsync(endPoint, method, buffer)
        .ContinueWith((bytes) =>
            {
                string jsonResponse = null;

                using (var reader = new StreamReader(new MemoryStream(bytes)))
                {
                    jsonResponse = reader.ReadToEnd();
                }

                return DeserializeResponse(jsonResponse);
            });
    }
}
于 2013-02-26T21:25:27.360 に答える
0

To use your existing code, just add a method that is intended to execute on the UI thread, and create your web request on a separate thread. When the web request is complete you call the final method on the UI thread. So, a simple version would be:

//do some stuff that wont block the ui thread here
ThreadPool.QueueUserWorkItem((o) => 
{
    IDictionary<string, object> result = 
        CreateWebRequest("lalala", "lol", "butts", true);
    BeginInvoke(OnAsyncWebRequestComplete, result);
}, null);

private void OnAsyncWebRequestComplete(IDictionary<string, object> result)
{
    //do some stuff on the UI thread here
}
于 2013-02-26T21:11:15.877 に答える