How can I set a timeout for an Async function that doesn't accept a cancellation token?

前端 未结 3 1987
有刺的猬
有刺的猬 2021-01-04 20:13

I have my web requests handled by this code;

Response = await Client.SendAsync(Message, HttpCompletionOption.ResponseHeadersRead, CToken);

3条回答
  •  醉酒成梦
    2021-01-04 20:41

    While you can rely on WithCancellation for reuse purposes, a simpler solution for a timeout (which doesn't throw OperationCanceledException) would be to create a timeout task with Task.Delay and wait for the first task to complete using Task.WhenAny:

    public static Task WithTimeout(this Task task, TimeSpan timeout)
    {
        var timeoutTask = Task.Delay(timeout).ContinueWith(_ => default(TResult), TaskContinuationOptions.ExecuteSynchronously);
        return Task.WhenAny(task, timeoutTask).Unwrap();
    }
    

    Or, if you want to throw an exception in case there's a timeout instead of just returning the default value (i.e. null):

    public static async Task WithTimeout(this Task task, TimeSpan timeout)
    {
        if (task == await Task.WhenAny(task, Task.Delay(timeout)))
        {
            return await task;
        }
        throw new TimeoutException();
    }
    

    And the usage would be:

    var content = await Response.Content.ReadAsStringAsync().WithTimeout(TimeSpan.FromSeconds(1));
    

提交回复
热议问题