views:

276

answers:

3

Trying to do basic webclient data pull in C#, and the methods are not available in visualstudio, and the code is not compiling.

        //snip
        WebClient client = new WebClient();
        byte[] resp = client.DownloadData(url);
        //snip

Error 1 'System.Net.WebClient' does not contain a definition for 'DownloadData' and no extension method 'DownloadData' accepting a first argument of type 'System.Net.WebClient' could be found (are you missing a using directive or an assembly reference?) C:\Users\Michael\Documents\Visual Studio 2008\Projects\search2\search2\MainPage.xaml.cs

I'm doing this in a c# file for a XAML/Silverlight project, but can't imagine why that would make a difference. I can not find any reference to this issue on the web, and I had something similar to this working last month, but in a regular ASP.NET page, not in a Silverlight app.

+2  A: 

Silverlight has a stripped-down/compact version of the .NET Framework. See MSDN's documentation for the WebClient in Silverlight to see it has very few methods compared to its counterpart in the full .NET Framework.

Rex M
I just found this: http://blogs.msdn.com/silverlight_sdk/archive/2008/04/01/using-webclient-and-httpwebrequest.aspx which seems to match up with the few methods I was seeing in intellisense - there's some notion of defining async callbacks. Argh - what a pain... (thanks)
mgkimsal
+2  A: 

Silverlight has only a subset of the functionality of the full .NET. More notably, it doesn't contain blocking methods for communication with web services. This makes the life of programmers a bit difficult, but it is a fantastic thing for users - you cannot (easily) write Silverlight applications that will hang when the server doesn't respond quickly.

If you can transfer the data as a text, you can use DownloadStringAsync method:

var wc = new WebClient();
wc.DownloadStringCompleted += (sender, e) => {
     string data = (string)e.Result;
     // Process the data here
   }
wc.DownloadStringAsync(new Uri(address));

If you need to transfer binary data, then you'll probably have to use HttpWebRequest class explicitly.

Tomas Petricek
A: 

You can best achieve what you want in Silverlight by using WebClient.OpenReadCompleted and OpenReadAsync. This will return a stream. You can use that directly, or copy the stream into a byte[] as described here for example: http://www.yoda.arachsys.com/csharp/readbinary.html

Also, beware that Silverlight's functionality for WebClient is NOT a subset of .NET's. If it was a subset, then things that they both do, they'd do the same. But this is not the case. For example, SL4's OpenReadAsync really is asynchronous. It doesn't block the calling thread at all. In .NET4, however, OpenReadAsync and DownloadDataAsync do partially block the calling thread, and block it worse while running in the debugger. To get a truly non-UI-blocking effect in .NET4, you need to run the download in a separate thread yourself. Furthermore, in Silverlight, DownloadProgressUpdated fires nicely throughout the download for OpenReadAsync. In .NET it doesn't. However .NET's DownloadDataAsync does fire DownloadProgressUpdated in a fairly similar way to Silverlight's OpenReadAsync.

So, if you want to achieve consistency between a WPF and Silverlight project, you can use OpenReadAsync directly on the SL side. On the WPF side, fire off a DownloadDataAsync in a separate thread:

Thread downloadThread = new Thread(new ThreadStart(() => wc.DownloadDataAsync(uri)));
downloadThread.Start();

Then in DownloadDataCompleted, create a MemoryStream from the returned byte[], if you'd rather have it in stream form. (I haven't found the additional overhead to affect performance significantly.)

Adrian