10

ポータブルクラスライブラリ内に、特定のURLにデータを投稿する次のメソッドがあります。この方法はうまく機能します。ただし、より積極的なタイムアウトを指定したいと思います(デフォルトは100秒です)。

Portable Class LibraryのHttpWebRequestクラスにTimeoutプロパティがないことを考えると、数秒以上かかる場合に呼び出しが破棄されるようにするにはどうすればよいですか?

public async Task<HttpResponse> PostAsync(Uri uri, string data)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";

    using (Stream requestStream = await request.GetRequestStreamAsync())
    {
        byte[] postBytes = Encoding.UTF8.GetBytes(data);
        requestStream.Write(postBytes, 0, postBytes.Length);
    }

    HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
    return new HttpResponse(response.StatusCode, await new StreamReader(response.GetResponseStream()).ReadToEndAsync());
}
4

2 に答える 2

24

以下のコードは、タイムアウトした場合は HttpWebResponse または null を返します。

HttpWebResponse response = await TaskWithTimeout(request.GetResponseAsync(), 100);
if(response != null)
{
  ....
}

Task<HttpWebResponse> TaskWithTimeout(Task<WebResponse> task, int duration)
{
    return Task.Factory.StartNew(() =>
    {
        bool b = task.Wait(duration);
        if (b) return (HttpWebResponse)task.Result;
        return null;
    });
}

- 編集 -

拡張メソッドを作成するとさらに良いでしょう

public static class SOExtensions
{
    public static Task<T> WithTimeout<T>(this Task<T> task, int duration)
    {
        return Task.Factory.StartNew(() =>
        {
            bool b = task.Wait(duration);
            if (b) return task.Result;
            return default(T);
        });
    }
}

使用法は次のとおりです。

var response = (HttpWebResponse)await request.GetResponseAsync().WithTimeout(1000);

--編集2--

それを行う別の方法

public async static Task<T> WithTimeout<T>(this Task<T> task, int duration)
{
    var retTask = await Task.WhenAny(task, Task.Delay(duration))
                            .ConfigureAwait(false);

    if (retTask is Task<T>) return task.Result;
    return default(T);
}
于 2012-12-12T11:49:22.727 に答える
0
// Abort the request if the timer fires. 
private static void TimeoutCallback(object state, bool timedOut) { 
    if (timedOut) {
        HttpWebRequest request = state as HttpWebRequest;
            if (request != null) {
              request.Abort();
        }
    }
}

はい、独自のタイムアウト メカニズムを実装するのは、クライアント アプリケーションの責任です。これは、タイムアウトを設定し、ThreadPool.RegisterWaitForSingleObject メソッドを使用する上記のコードから実行できます。詳細については、 http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspxを参照してください。基本的に、GetResponse、BeginGetResponse、EndGetResponse、GetRequestStream、BeginGetRequestStream、または EndGetRequestStream からの中止を行います。

于 2012-12-12T11:05:52.837 に答える