2012-10-18 32 views
5

मैं आरएसएस वस्तुओं का एक समूह लाने के लिए प्रतिक्रियाशील एक्सटेंशन के साथ प्रयोग कर रहा हूं। मैंने खुद को टिम ग्रीनफील्ड द्वारा ब्लॉग पोस्ट पर आधारित किया: Silverlight Rx DataClient within MVVMआरएक्स पुनः प्रयास() अपेक्षित काम नहीं कर रहा है

मैं इसे डेस्कटॉप एप्लिकेशन के भीतर उपयोग कर रहा हूं, लेकिन कोड समान है।

मेरी समस्या यह है कि Retry() फ़ंक्शंस को समझने में समस्या है। ऐसा लगता है कि मैं जो अपेक्षा करता हूं वह कर रहा हूं और जिस पर मैं इसकी अपेक्षा कर रहा हूं।

var items = new List<RssItem>(); 
WebHelper.DownloadXmlFileAsync<RssItem>(new Uri(URI), "item") 
    .Retry(2) 
    .Finally(PublishResults) 
    .Subscribe(items.Add, ProcessError,() => ProcessCompleted(items)); 

जब मैं एक वैध यूआरआई में जाता हूं, तो यह बिना किसी समस्या के काम करता है। जब मैं यूआरआई में एक टाइपो बना देता हूं तो यह ProcessError() फ़ंक्शन के माध्यम से 404 त्रुटि की रिपोर्ट करता है, जैसा कि कोई अपेक्षा करता है, लेकिन यह केवल एक बार रिपोर्ट किया जाता है। मैं यह त्रुटि दो बार दिखाने की उम्मीद करता।

तो ऐसा लगता है कि Retry() फ़ंक्शन मेरे वेब अनुरोध पर काम नहीं कर रहा है, लेकिन ऐसा लगता है कि यह वास्तव में Subscribe() पर भेजे गए कार्यों पर लागू होता है। हालांकि मैं गलत हो सकता था।

मैं कैसे सुनिश्चित कर सकता हूं कि Retry() कॉल वेब अनुरोध पर लागू होता है?

अतिरिक्त कोड:

public static class WebHelper 
{ 
    public static HttpWebRequest CreateHttp(Uri uri) 
    { 
     return CreateHttp(uri, "GET"); 
    } 

    public static HttpWebRequest CreateHttp(Uri uri, string method) 
    { 
     if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) 
     { 
      throw new ArgumentException("The specified URI does not use HTTP or HTTPS.", "uri"); 
     } 

     var request = (HttpWebRequest)WebRequest.Create(uri); 
     request.Method = method; 

     return request; 
    } 

    public static IObservable<T> DownloadXmlFileAsync<T>(Uri uri, string elementName) where T : class 
    { 
     return (from request in Observable.Return(CreateHttp(uri)) 
       from response in Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)() 
       let stream = response.GetResponseStream() 
       where stream != null 
       from item in XmlReader.Create(stream).GetXmlItem<T>(elementName).ToObservable() 
       select item); 
    } 
} 

public static class XmlExtensions 
{ 
    public static IEnumerable<T> GetXmlItem<T>(this XmlReader reader, string elementName) where T : class 
    { 
     var serializer = new XmlSerializer(typeof (T)); 
     while (reader.GoToElement(elementName)) 
     { 
      yield return serializer.Deserialize(reader) as T; 
     } 
    } 

    public static bool GoToElement(this XmlReader reader, string elementName) 
    { 
     do 
     { 
      if (reader.NodeType == XmlNodeType.Element && reader.Name == elementName) 
      { 
       return true; 
      } 
     } while (reader.Read()); 

     return false; 
    } 
} 

XmlRoot("item")] 
public class RssItem 
{ 
    [XmlElement("description")] 
    public string Description { get; set; } 

    [XmlElement("link")] 
    public string Link { get; set; } 

    [XmlElement("pubDate")] 
    public string PublishDate { get; set; } 

    [XmlElement("title")] 
    public string Title { get; set; } 

    public override string ToString() 
    { 
     return string.Format("Title: {0}", Title); 
    } 
} 

उत्तर

11

दृश्यों के लिए आरएक्स व्याकरण के रूप में परिभाषित किया गया है:

OnNext * (OnError | OnCompleted)?

को प्राप्त करना या तो एक OnError या एक OnCompleted संकेत अनुक्रम और पाइपलाइन पर सदस्यता के अंत की उम्मीद कर रहे गिराया जाना है।

ऑपरेटरों के संदर्भ में:

observable.Retry(n) है: एक OnError प्राप्त होने पर observable में पुन: सब्सक्राइब, एन बार तक।

observable.Finally(action) है: OnError|OnCompleted

प्राप्त पुन: प्रयास ठंड observables साथ प्रयोग किया जा करने के लिए है पर action निष्पादित (Lee Campbella good post on this है) जहां सदस्यता अनिवार्य स्रोत शुरू करने के लिए कारण बनता है।

इसी प्रकार Repeat बिल्कुल Retry जैसा है, इसे छोड़कर OnCompleted प्राप्त करने के लिए पुन: सदस्यता लेता है।

कार्रवाई में यह देखने के लिए, हम एक अवलोकन कर सकते हैं जो पहले एन बार के लिए "असफल" होगा, और फिर सफल होगा। अब कुछ कोड के लिए:

private static IObservable<int> ErrorProducer(int i) 
    { 
     int count = 0; 
     return Observable.Create<int>(observer => 
     { 
      Console.WriteLine("Doing work"); 

      if (count++ < i) 
      { 
       Console.WriteLine("Failed"); 
       observer.OnError(new Exception()); 
      } 
      else 
      { 
       Console.WriteLine("Done"); 
       observer.OnNext(count); 
       observer.OnCompleted();      
      } 
      return Disposable.Empty; 
     }); 
    } 

एक निर्माता के लिए जो हमेशा विफल रहता है:

 print(ErrorProducer(3).Retry(2)); 

देता है:

Doing work <-- Subscription 
Failed 
Doing work <-- Resubscription 
Failed 
OnError(System.Exception) 
Finally 

एक निर्माता है जो अंत में सफल होता है के लिए:

print(ErrorProducer(2).Retry(3)); 

Doing work 
Failed 
Doing work 
Failed 
Doing work 
Done 
OnNext(3) <-- Succeeded 
OnCompleted() 
Finally 

यदि आप वाई चाहते थे हमारी प्रक्रिया त्रुटि फ़ंक्शन को जितनी बार इसे रीट्रीज़ कहा जाता है, इसे Retry से पहले रखा जाना चाहिए।

अर्थात, seq.Do(value => { }, exception => { }).Retry(n)

आप गर्म/ठंडा observables का उपयोग कर, और Rx के साथ async पद्धति का उपयोग कर अपनी समझ को स्पष्ट करने के लिए पर पढ़ सकते हैं।

+2

आपके उत्तर ने कुछ अच्छी अंतर्दृष्टि प्रदान की और मुझे कुछ विशिष्ट खोजशब्दों के साथ इंटरनेट की खोज करने की इजाजत दी जिसके परिणामस्वरूप http://social.msdn.microsoft.com/Forums/da-DK/rx/thread/96a06e27-9c02-4177 -ae6a-04b8a7f966e5 जिसने मुझे अवलोकन के काम में थोड़ा और अंतर्दृष्टि दी। – Jensen

+0

@ जेन्सेनसोमर ग्लेड मैं मदद की हो सकती है। अपनी समस्या के सटीक कारण के बारे में बहुत विशिष्ट नहीं होने के बारे में खेद है। आरएक्स लगाने पर दस्तावेज़ीकरण दुर्लभ है, और मुझे उम्मीद है कि ये सामान्य उत्तर किसी ऐसे व्यक्ति के लिए उपयोग किए जा सकते हैं जो भविष्य में आरएक्स सीखने की कोशिश कर रहा है। – Asti

+0

यदि हर कोई आरएक्स के रूप में बाहर निकलेगा, तो मुझे यकीन है कि उचित दस्तावेज और बड़े उपयोग-मामले उदाहरण निकट भविष्य में पॉप अप होंगे। :-) – Jensen

4

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

जैसा कि एस्टी बताते हैं, आप केवल एक बार अनुक्रम को समाप्त कर सकते हैं। यह समाप्ति या तो एक त्रुटि या पूरा हो सकता है (ऑनरर | चालू)।

हालांकि आपको घोंसला वाले दृश्यों को रोकने के लिए कुछ भी नहीं है! यदि आप कई त्रुटि संदेशों को देखना चाहते हैं तो एक परिदृश्य पर विचार करें जहां आपने IObservable<IObservable<T>> लौटाया था। आंतरिक अनुक्रम डेटा अनुक्रम (वर्तमान में आपके पास अनुक्रम) है। जब यह अनुक्रम त्रुटियों का उपयोग तब किया जा सकता है, तो बाहरी अनुक्रम एक नया आंतरिक डेटा अनुक्रम उत्पन्न कर सकता है।

यह थोड़ा अजीब लग सकता है, लेकिन यह आरएक्स में एक समर्थित अवधारणा है क्योंकि मर्ज और स्विच जैसे ऑपरेटर पहले से ही इन नेस्टेड अनुक्रमों को पूरा करते हैं। आरएक्स की यह शैली में Sequences of Coincidence अध्याय

में अधिक विस्तार से Nested Sequences पैराग्राफ में मेरी किताब, IntroToRx में छुआ और उसके बाद फिर से है मैं यह कैसे भविष्य में RX के अन्य संभावनाओं को देखने के लिए आप में मदद करता है उम्मीद है।

संबंधित मुद्दे