4

responseObjectTask.Factory.FromAsync() を使用して宣言するとハングする、このようなメソッドがあります

private async Task<string> post(string url, string postdata)
        {
            var request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
            request.Method = "POST";

            // this works
            Task<Stream> requestStream = Task<Stream>.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, request);
            var sw = new StreamWriter(requestStream.Result);
            byte[] data = Encoding.UTF8.GetBytes(postdata);
            await requestStream.Result.WriteAsync(data, 0, data.Length);

            // this hangs
            Task<WebResponse> responseObject = Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, request); // Hangs here
            // Doesn't get to here
            var responseStream = responseObject.Result.GetResponseStream();
            var sr = new StreamReader(responseStream);
            string received = await sr.ReadToEndAsync();

            return received;
}

次のように、Begin/End メソッドを手動で実行すると問題なく動作します。

        request.BeginGetRequestStream(async ar =>
        {
            var requestStream = request.EndGetRequestStream(ar);
            using (var sw = new StreamWriter(requestStream))
            {
                byte[] data = Encoding.UTF8.GetBytes(postdata);
                await requestStream.WriteAsync(data, 0, data.Length);
            }

            request.BeginGetResponse(async a =>
            {
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(a);
                var responseStream = response.GetResponseStream();
                using (var sr = new StreamReader(responseStream))
                {
                    string received = await sr.ReadToEndAsync();
                }

            }, null);
        }, null);

ただし、その場合、ReadToEndAsync() は別のスレッドで実行され、メソッドが結果を返すようにしたいのですが、BeginGetResponse コールバックが終了する前にメソッドが返されるため、これは不可能です。

この時点で、私はこれをひどく間違っており、これを完全に間違った方法で行っていると思うので、どんな助けも大歓迎です.

4

1 に答える 1

11

まず、非同期メソッドで「.Result」を使用しないでください。これにより、メソッドを実行しているスレッドがブロックされます。代わりに「await」を使用して、結果が取得されたときにスレッドがメソッドに戻るようにします。

コードの問題は、リクエスト ストリームを開いているが、決して閉じていないことです。では、いつリクエストを完了して送信することを期待する必要がありますか? リクエストがタイムアウトになるまで、常に追加の入力が期待されます。また、コンテンツ タイプとコンテンツ長を設定していません。

private async Task<string> post(string url, string postdata)
    {
        var request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
        request.Method = "POST";

        byte[] data = Encoding.UTF8.GetBytes(postdata);
        request.ContentLength = data.Length;

        using (var requestStream = await Task<Stream>.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, request))
        {
            await requestStream.WriteAsync(data, 0, data.Length);
        }


        WebResponse responseObject = await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, request);
        var responseStream = responseObject.GetResponseStream();
        var sr = new StreamReader(responseStream);
        string received = await sr.ReadToEndAsync();

        return received;
}
于 2012-12-31T07:45:38.623 に答える