WebClient.AsyncDownloadString() - 有没有办法指定超时?

时间:2016-05-07 03:52:52

标签: .net f# webclient

我还没有找到指定操作超时的方法 - 请参阅代码段以了解我尝试实现的目标。

type ResponseKind =
    | Json of string
    | Error of Exception
    | Timeout

let download (wclient : WebClient) (timeout : int option) (base_url : Uri) (sub_url : string) : Async<ResponseKind> =
    async {
        let target_uri = Uri(base_url, sub_url)
        try
            let! result = wclient.AsyncDownloadString(target_uri)
            return ResponseKind.Json result
        with
        | :? TimeoutException -> 
            return ResponseKind.Timeout
        | _ as ex ->
            return ResponseKind.Error ex
    }

现在,我知道有很多其他方法可以实现相同的目标,例如:使用WebRequest代替。但也许这只是对我的一个简单疏忽,而不是找出如何设置操作超时。

想法?

更新

代表我进行的进一步调查使我找到FSSnippet ,它与要执行的任务并行使用超时任务。

在我的上下文中重用该方法,产生了我的代码的修改版本:

type ResponseKind =
    | Json of string
    | Error of Exception
    | Timeout

let await_download_with_timeout (task : Task<string>) (timeout : int) : Async<ResponseKind>=
    async {
        use cts = new CancellationTokenSource()
        use timer = Task.Delay (timeout,cts.Token)
        let! completed =
            Task.WhenAny(task,timer)
            |> Async.AwaitTask
        if completed = (task :> Task)
        then
            cts.Cancel()
            let! result = Async.AwaitTask task
            if task.IsCompleted
            then
                return ResponseKind.Json result
            else
                return ResponseKind.Error (task.Exception)
        else
            return ResponseKind.Timeout
    }

let download (wclient : WebClient) (timeout : int option) (base_url : Uri) (sub_url : string) : Async<ResponseKind> =
    async {
        let target_uri = Uri(base_url, sub_url)
        try
            match timeout with
            | Some t ->
                let dtask = wclient.DownloadStringTaskAsync(target_uri)
                let! result = await_download_with_timeout dtask t
                return result
            | None ->
                let! result = wclient.AsyncDownloadString(target_uri)
                return ResponseKind.Json result
        with
        | :? TimeoutException -> 
            return ResponseKind.Timeout
        | _ as ex ->
            return ResponseKind.Error ex
    }

现在,问题仍然存在,我不确定我是否发现其他错误是正常的。

1 个答案:

答案 0 :(得分:0)

我有这个经过充分测试的代码,但它的定位是HttpWebRequest而不是WebClient;我相信它可以完全适合您的需求:

type System.Net.WebRequest with
  member req.AsyncGetResponseWithTimeout () =
    let impl = async {
      let iar = req.BeginGetResponse (null, null)
      let! success = Async.AwaitIAsyncResult (iar, req.Timeout)
      return if success then req.EndGetResponse iar
             else req.Abort ()
                  raise (System.Net.WebException "The operation has timed out") }
    Async.TryCancelled (impl, fun _ -> req.Abort ())