2016-05-07 10 views
0

Ich habe keine Möglichkeit gefunden, das Zeitlimit für die Operation festzulegen. Sehen Sie sich das Code-Snippet an, um zu sehen, was ich erreichen möchte.WebClient.AsyncDownloadString() - Gibt es eine Möglichkeit, ein Timeout festzulegen?

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 
    } 

Nun, ich bin mir bewusst, dass es Myriaden von anderen Möglichkeiten sind, das gleiche zu erreichen, z.B. Verwenden Sie stattdessen WebRequest. Aber vielleicht ist es nur ein einfaches Versehen von mir, nicht herauszufinden, wie man eine Zeitüberschreitung bei der Operation einstellt.

Ideen?

aktualisiert

Weitere Untersuchungen in meinem Namen führten mich zu einem FSSnippet, die eine Timeout Aufgabe parallel zu der Task ausgeführt werden verwendet.

diesen Ansatz in meinem Kontext wiederverwendet, ergab eine modifizierte Version von meinem Code:

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 
    } 

nun noch das Problem, dass ich nicht sicher bin, ob meine Erkennung von etwas anderes falsch in Ordnung geht.

+0

http://stackoverflow.com/questions/1789627/how-to-change-the-timeout-on-a-net-webclient-object - Dang - Ich habe das nicht gefunden, bevor ich meine Frage geschrieben habe - also meine Frage ist ein Duplikat - Entschuldigung. – BitTickler

+0

Das funktioniert möglicherweise nicht bei Async. – Ringil

Antwort

0

Ich habe diesen Code, der gut getestet wurde, aber orientiert sich an HttpWebRequest statt WebClient; Ich bin sicher, es kann trivialerweise auf Ihre Bedürfnisse werden:

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()) 
Verwandte Themen