2012-12-12 37 views
8

पोर्टेबल क्लास लाइब्रेरी के अंदर, मेरे पास निम्न विधि है जो एक विशिष्ट यूआरएल को डेटा पोस्ट करती है। विधि महान काम करता है। हालांकि मैं एक अधिक आक्रामक टाइमआउट निर्दिष्ट करना चाहता हूं (डिफ़ॉल्ट 100 सेकंड है)।HttpWebRequest के लिए एक अधिक आक्रामक टाइमआउट को परिभाषित करने के लिए कैसे?

यह ध्यान में रखते हुए कि पोर्टेबल क्लास लाइब्रेरी से HttpWebRequest क्लास पर कोई टाइमआउट संपत्ति नहीं है, मैं यह कैसे सुनिश्चित कर सकता हूं कि कॉल को कुछ सेकेंड से अधिक समय तक छोड़ दिया जाए?

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()); 
} 
+0

HttpWebRequest.Timeout = 20000; ? यह काफी स्मार्ट है? –

उत्तर

20

कोड के नीचे या तो समय समाप्त होने पर एक HttpWebResponse या शून्य वापस कर देगा।

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; 
    }); 
} 

--EDIT--

एक विस्तार विधि बनाना भी बेहतर होगा

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); 

--EDIT 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); 
} 
+0

वाह! दिलचस्प विचार! मुझे यह पसंद है क्योंकि यह सुरुचिपूर्ण और समझने में अपेक्षाकृत आसान है। लेकिन मुझे आश्चर्य है कि क्या कार्य है। प्रतीक्षा एक अवरुद्ध ऑपरेशन है (यानी जब तक यह लौटा नहीं जाता है तब तक एक धागा पकड़ने जा रहा है)। – Martin

+1

@ मार्टिन हां यह एक अवरुद्ध ऑपरेशन है, लेकिन यह किसी अन्य कार्य में किया जाता है (देखें: 'टास्क.फैक्टरी.स्टार्टन्यू') और अनुरोध का इंतजार करने से अलग नहीं होगा। GetResponseAsync() ' –

+0

मैं सहमत हूं! यह थ्रेडपूल पर सिर्फ एक और धागे है। मुझे आश्चर्य है कि क्या हम इसे गैर-अवरुद्ध कर सकते हैं। अवरुद्ध करना या नहीं, यह एक बहुत चालाक समाधान है। – Martin

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(); 
     } 
    } 
} 

हाँ यह अपने आप टाइम-आउट तंत्र लागू करने के लिए क्लाइंट अनुप्रयोग की जिम्मेदारी है। आप इसे उपरोक्त कोड से कर सकते हैं जो टाइमआउट सेट करता है और थ्रेडपूल का उपयोग करता है। रजिस्ट्रार WaitForSingleObject विधि। पूर्ण विवरण के लिए http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspx देखें। अनिवार्य रूप से यह GetResponse, BeginGetResponse, EndGetResponse, GetRequestStream, BeginGetRequestStream, या EndGetRequestStream से एक निरस्त करता है।