0

I have tried to add a foreach loop around a WebClient task, but it does not seem to work. I have done a bit of research and found that there are some clean dirty Methods to fix this like sending the system to sleep for one second, I would like a more structured solution. If there is no solution How else can I read a RSS feed from the internet with W8 phone.

foreach (string rssFeed in lstRSSFeeds)
{
    // our web downloader
    WebClient downloader = new WebClient();

    // our web address to download, notice the UriKind.Absolute
    Uri uri = new Uri(rssFeed, UriKind.Absolute);

    // we need to wait for the file to download completely, so lets hook the DownloadComplete Event
    downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(FileDownloadComplete);

    // start the download
    downloader.DownloadStringAsync(uri);
}
rechandler
  • 756
  • 8
  • 22
user3795349
  • 314
  • 2
  • 16
  • Is this code sample complete, it doesn't appear you are using the rssFeed variable at all in the loop, so why the loop at all? – Ryan Mann Oct 28 '14 at 15:38
  • 3
    You said it "does not seem to work". Are you getting a specific error message, or is it running to completion but not giving the desired results, or what? – Ryan Nigro Oct 28 '14 at 15:38
  • Could it be that your actual problem is calling the async method of the WebClient inside a loop? I'm not sure about limitations on the WP8 platform but usually this can be solved using [await](http://msdn.microsoft.com/en-us/library/hh156528.aspx) – Filburt Oct 28 '14 at 15:38
  • take a look at this previous `SO` posting not sure if it applies to what your are trying to do but looks like it may http://stackoverflow.com/questions/13505967/multiple-parallel-execution-of-webclient-as-task-tpl – MethodMan Oct 28 '14 at 15:41
  • You're overriding `downloader` variable all the time. – rechandler Oct 28 '14 at 15:41
  • 2
    @J.Marciniak He's not *overriding* it, no. The variable is leaving scope and being re-declared in each iteration of the loop. That is something different, and also not a problem at all. – Servy Oct 28 '14 at 15:43
  • @Servy yeah... you're right. I'm tried, sorry. – rechandler Oct 28 '14 at 15:44
  • Don't forget that `WebClient` is disposable - so you need to dispose of your instances. – Enigmativity Oct 29 '14 at 02:06

2 Answers2

0

If you want to download multiple files, it would be best to implement some kind of download manager. It might sound difficult, but I assure you it is not.

For example:

We can implement a Download Manager by creating a List of KeyValuePair. The KeyValuePair will have a Key which is basically the Website's URL and Value of the Website's HTML (or downloaded content).

We will use your foreach scheme to download the files.


public partial class MainPage : PhoneApplicationPage
{

    // our simple download manager
    List<KeyValuePair<string, string>> DownloadManager = new List<KeyValuePair<string, string>>();

    // Constructor
    public MainPage()
    {
        InitializeComponent();

        // create our list of websites to download
        List<string> lstRSSFeeds = new List<string>();

        // lets add 3 web sites
        lstRSSFeeds.Add("http://www.google.com");
        lstRSSFeeds.Add("http://www.msn.com");
        lstRSSFeeds.Add("http://www.chubosaurus.com");

        // for each website in the list, download its data
        foreach (string rssFeed in lstRSSFeeds)
        {
            // our web downloader
            WebClient downloader = new WebClient();

            // our web address to download, notice the UriKind.Absolute
            Uri uri = new Uri(rssFeed, UriKind.Absolute);
            downloader.BaseAddress = uri.ToString();

            // we need to wait for the file to download completely, so lets hook the DownloadComplete Event
            downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(FileDownloadComplete);

            // start the download
            downloader.DownloadStringAsync(uri);
        }
    }

    // this event will fire if the download was successful
    // we will save all the data to the DownloadManager
    void FileDownloadComplete(object sender, DownloadStringCompletedEventArgs e)
    {
        // error check
        if (!e.Cancelled && e.Error == null)
        {
             string uri = ((WebClient)sender).BaseAddress;   // set the key to the base address (url)
             string html = e.Result;                         // save the html 

             // create the KeyValuePair (this will save all the html and be indexed by the url)
             KeyValuePair<string, string> site_data = new KeyValuePair<string, string>(uri, html);

             // add the KeyValuePair to our download manager
             DownloadManager.Add(site_data);
        }            
    }
}

Now set a break point. And watch the DownloadManager as it fills up with data. Here's a screenshot of the DownloadManager, notice how organize it is. The website/data combination should be very simple for you to understand.

Click Here For Full Size Image enter image description here

Chubosaurus Software
  • 8,133
  • 2
  • 20
  • 26
0

I would use the Microsoft Reactive Framework (Rx) for this. It handles all the asynchronous calls for you and can be used to clean up the WebClient (which is an IDisposable).

Here's how:

var query =
    from rssFeed in lstRSSFeeds.ToObservable(Scheduler.Default)
    from content in Observable.Using(
        () => new WebClient(),
        wc => Observable.FromAsync(
           () => wc.DownloadStringTaskAsync(new Uri(rssFeed, UriKind.Absolute))))
    select new { rssFeed, content };

query.Subscribe(result =>
{
    // do something with each
    // `result.rssFee` & `result.content`
});

Rx is basically an asynchronous LINQ query that uses Observables rather than Enumerables.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172