How can I get the URL in OpenReadCompletedEvent when I use webclient - c#

How can I get the URL in OpenReadCompletedEvent when I use webclient.
WebClient webClient = new WebClient();
webClient.OpenReadAsync(url); // in event method I want get this url
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
// I want get the url here,
// How to do this?
string strStream = reader.ReadToEnd();
}
}
}
Thank you!

WebClient webClient = new WebClient();
webClient.BaseAddress = "http://hhh.com";
webClient.OpenReadAsync(new Uri("http://hhh.com")); // in event method I want get this url
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
And:
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
// I want get the url here,
// How to do this?
var client = sender as WebClient;
if (client != null)
{
var url = client.BaseAddress; //returns hhh.com
}
string strStream = reader.ReadToEnd();
}
}

Anton Sizikov's solution is good, but will only work if the URL is absolute (like http://hhh.com). If using a relative URL, .NET will automatically merge the base address with the relative URL (therefore potentially resulting in an invalid URL).
To send a value to the OpenReadCompleted event handler, you're supposed to use this OpenRead overload to provide a custom token (in this case, your URL): http://msdn.microsoft.com/en-us/library/ms144212(v=vs.95).aspx
WebClient webClient = new WebClient();
webClient.OpenReadAsync(new Uri("http://hhh.com"), "http://hhh.com");
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
Then to retrieve the value:
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
var url = (string)e.UserState;
string strStream = reader.ReadToEnd();
}
}
}

For me even a simpler variation from the above works fine
private void CardInfoDown_Completed(object sender, DownloadStringCompletedEventArgs e)
{
string url;
if (e.Error == null)
{
url = (string)e.UserState;
}
// ...
}

Related

Why doesn't delegate call the function?

1: Can someone explain the last line of the first function to me?
2: The second function doesn't work. Please tell me why.The PHP script is fetching the data.
I edited the code to get this, but the app now crashes with a System nullreferenceexception.
Please help.
private void checkbutton_Click(object sender, RoutedEventArgs e)
{
statustext.Text = "Checking for new score";
var webclient = new WebClient();
webclient.OpenReadCompleted += new OpenReadCompletedEventHandler(getscores_OpenReadCompleted);
webclient.OpenReadAsync(new Uri("http://example.com/get.php?"+DateTime.Now));
}
void getscores_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
StreamReader s = null;
Stream reply=null;
try
{
reply = (Stream)e.Result;
s = new StreamReader(reply);
}
catch
{
statustext.Text = "ERROR IN FETCHING";
}
scorebox.Text = s.ReadToEnd();
statustext.Text = "DoNE";
}
The last line of the first method is attaching a handler to an event. It is saying that when the OpenReadCompleted event fires, that is to say when the read completes, the getscores_OpenReadCompleted method should be called.
The getscores_OpenReadCompleted doesn't work because it's trying to access a UI element from a non-UI thread.
You're also adding the handler after starting the asynchronous operation, so while it's unlikely, it's certainly possible that the operation completes very quickly and the event is fired before you add the handler. While this situation would be very unusual, it's fixed very quickly and easily by simply adding the handler before you start the asynchronous operation.
There are a couple of issues here:
Register the delegate before the call to OpenReadAsync
Read the stream from the event arguments and close the stream when you're done.
private void checkbutton_Click(object sender, RoutedEventArgs e)
{
statustext.Text = "Checking for new score";
var webclient = new WebClient();
webclient.OpenReadCompleted += new OpenReadCompletedEventHandler(getscores_OpenReadCompleted);
webclient.OpenReadAsync(new Uri("http://example.com/get.php?"+DateTime.Now));
}
void getscores_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
Stream reply = null;
StreamReader s = null;
string outputText = string.Empty;
try
{
reply = (Stream)e.Result;
s = new StreamReader(reply);
outputText = s.ReadToEnd();
}
finally
{
if (s != null)
{
s.Close();
}
if (reply != null)
{
reply.Close();
}
}
statustext.Text = outputText;
}
See the usage of the OpenReadAsync method here:
http://msdn.microsoft.com/en-us/library/system.net.openreadcompletedeventhandler(v=vs.110).aspx
and here
http://msdn.microsoft.com/en-us/library/ms144211(v=vs.110).aspx

How do I check if WebClient download is completed before I execute a function?

I am trying to get to JSON files from different URLs. How do I make sure both files are downloaded completely before I try to execute something else.
My code looks something like this:
WebClient Url1 = new WebClient();
Url1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url1_DownloadStringCompleted);
Url1.DownloadStringAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
Url2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url2_DownloadStringCompleted);
Url2.DownloadStringAsync(new Uri("http://anotherexample.com"));
DoSomethingWithJson();
void Url1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json1 = JObject.Parse(e.Result);
}
void Url2_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json2 = JObject.Parse(e.Result);
}
Right now, what happens is json1 and json2 returns null values whenever I try to display them in a MessageBox inside DoSomethingWithJson(), and I am assuming this might be because they haven't been downloaded completely.
The DownloadStringAsync() method is returning before the string is downloaded because it's an asynchronous method. If you move the DoSomethingWithJson() method to your completed handlers then it will be called once the request is completed. You may want to add logic to the DoSomethingWithJson() method so that it only does it's work if all the variables it needs are populated (If indeed you need them all to be populated before you start doing anything else).
WebClient Url1 = new WebClient();
Url1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url1_DownloadStringCompleted);
Url1.DownloadStringAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
Url2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url2_DownloadStringCompleted);
Url2.DownloadStringAsync(new Uri("http://anotherexample.com"));
var json1Done = false;
var json2Done = false;
void Url1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json1 = JObject.Parse(e.Result);
json1Done = true;
if(json1Done && json2Done)
{
DoSomethingWithJson();
}
}
void Url2_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json2 = JObject.Parse(e.Result);
json2Done = true;
if(json1Done && json2Done)
{
DoSomethingWithJson();
}
}
Alternatively, if you are using .Net 4.5 then you could use the new async/await features:
WebClient Url1 = new WebClient();
var json1Task = Url1.DownloadStringTaskAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
var json2Task = Url2.DownloadStringTaskAsync(new Uri("http://anotherexample.com"));
json1 = await json1Task;
json2 = await json2Task;
DoSomethingWithJson();

Downloading HTML source code with DownloadStringAsync doesn't download entire source on WP8

I'm trying to download some HTML source code with DownloadStringAsync. My code looks like this:
WebClient client = new WebClient();
client.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(DownloadStringCallback2);
client.DownloadStringAsync(new Uri(url));
private void DownloadStringCallback2(Object sender, DownloadStringCompletedEventArgs e)
{
source = (string)e.Result;
if (!source.Contains("<!-- Inline markers start rendering here. -->"))
MessageBox.Show("Nope");
else
MessageBox.Show("Worked");
}
If I look at the variable "source" I can see that some of the source is there, but not all. However, if I do something like this it works:
while (true)
{
source = wb.DownloadString(url);
if (source.Contains("<!-- Inline markers start rendering here. -->"))
break;
}
Unfortunately I can't use that approach since WP8 don't have DownloadString.
Does anyone know how to fix this or if there is a better approach?
This function should help you out
public static Task<string> DownloadString(Uri url)
{
var tcs = new TaskCompletionSource<string>();
var wc = new WebClient();
wc.DownloadStringCompleted += (s, e) =>
{
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};
wc.DownloadStringAsync(url);
return tcs.Task;
}

web client DownloadFileCompleted get file name

I tried to download file like this:
WebClient _downloadClient = new WebClient();
_downloadClient.DownloadFileCompleted += DownloadFileCompleted;
_downloadClient.DownloadFileAsync(current.url, _filename);
// ...
And after downloading I need to start another process with download file, I tried to use DownloadFileCompleted event.
void DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
throw e.Error;
}
if (!_downloadFileVersion.Any())
{
complited = true;
}
DownloadFile();
}
But, i cannot know name of downloaded file from AsyncCompletedEventArgs , I made my own
public class DownloadCompliteEventArgs: EventArgs
{
private string _fileName;
public string fileName
{
get
{
return _fileName;
}
set
{
_fileName = value;
}
}
public DownloadCompliteEventArgs(string name)
{
fileName = name;
}
}
But I cannot understand how call my event instead DownloadFileCompleted
Sorry if it's nood question
One way is to create a closure.
WebClient _downloadClient = new WebClient();
_downloadClient.DownloadFileCompleted += DownloadFileCompleted(_filename);
_downloadClient.DownloadFileAsync(current.url, _filename);
This means your DownloadFileCompleted needs to return the event handler.
public AsyncCompletedEventHandler DownloadFileCompleted(string filename)
{
Action<object, AsyncCompletedEventArgs> action = (sender, e) =>
{
var _filename = filename;
if (e.Error != null)
{
throw e.Error;
}
if (!_downloadFileVersion.Any())
{
complited = true;
}
DownloadFile();
};
return new AsyncCompletedEventHandler(action);
}
The reason I create the variable called _filename is so that the filename variable passed into the DownloadFileComplete method is captured and stored in the closure. If you didn't do this you wouldn't have access to the filename variable within the closure.
I was playing around DownloadFileCompleted to get the file path/file name From the event. I've tried the above solution also but It was not like my expectation then i fond the solution by adding Querystring value, Here i would like to share the code with you.
string fileIdentifier="value to remember";
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler (DownloadFileCompleted);
webClient.QueryString.Add("file", fileIdentifier); // here you can add values
webClient.DownloadFileAsync(new Uri((string)dyndwnldfile.path), localFilePath);
And the event can be defined as like this:
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
string fileIdentifier= ((System.Net.WebClient)(sender)).QueryString["file"];
// process with fileIdentifier
}

When using a delegate, is there a way to get hold of the object response?

As an example:
WebClient.DownloadStringAsync Method (Uri)
Normal code:
private void wcDownloadStringCompleted(
object sender, DownloadStringCompletedEventArgs e)
{
// The result is in e.Result
string fileContent = (string)e.Result;
}
public void GetFile(string fileUrl)
{
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(wcDownloadStringCompleted);
wc.DownloadStringAsync(new Uri(fileUrl));
}
}
But if we use an anonymous delegate like:
public void GetFile(string fileUrl)
{
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted +=
delegate {
// How do I get the hold of e.Result here?
};
wc.DownloadStringAsync(new Uri(fileUrl));
}
}
How do I get the hold of e.Result there?
wc.DownloadStringCompleted +=
(s, e) => {
var result = e.Result;
};
or if you like the delegate syntax
wc.DownloadStringCompleted +=
delegate(object s, DownloadStringCompletedEventArgs e) {
var result = e.Result;
};
If you really want to use an anonymous delegate instead of lambda:
wc.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
{
// your code
}
You should be able to use the following:
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted += (s, e) =>
{
string fileContent = (string)e.Result;
};
wc.DownloadStringAsync(new Uri(fileUrl));
}
The other answers use a lambda expression but, for completeness, note that you can also specify the delegate's arguments:
wc.DownloadStringCompleted +=
delegate(object sender, DownloadStringCompletedEventArgs e) {
// Use e.Result here.
};
Try this:
public void GetFile(string fileUrl)
{
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted +=
(s, e) => {
// Now you have access to `e.Result` here.
};
wc.DownloadStringAsync(new Uri(fileUrl));
}
}

Categories