Using webclient in a method - c#

I'm looking into how i can create a webclient method that i can reuse in my code. Now the below code would call client_DownloadStringCompleted and i would have to deal with the returned data there, but i'd like to do it in the request method so i can return it.
private string request(string json, string url) {
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri(url);
}

The WebClient call is asynchronous, and it's that for a reason. The reason is usually to not block the UI thread during the wait time when the call has been initiated and the result has come back through the wire.
I think you are making a design mistake by enforcing an old school blocking call.
See my response in this question for solutions. WebClient - wait until file has downloaded

As the web request is performed asynchronously there isn't an easy way to have that method block and only return when (if?) the response is received. (There is a way to do this but it is recommended against for perf, usability and maintainability reasons.)
Instead you should write code that is designed to be run asynchronously.
The general pattern for your situation is to specify a callback method which takes an action as a final parameter.
The simplest way to implement the action is to take a single parameter which is the webresponse object. To aid code reuse and separation of concerns you'll probably want to move to having the action take a tuple of an Exception or the raw (or possibly formatted) response content.
You'll want to write your method something like:
private string request(string json,
string url,
Action<Exception, string> callback)
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
// add better error handling than this!!!
try
{
callback(e.Error, e.Result);
}
catch (Exception exc)
{
callback(exc, null);
}
};
client.DownloadStringAsync(new Uri(url);
}
Alternativey, you could use the async ctp http://msdn.microsoft.com/en-us/vstudio/gg316360

This sychronous method can be used, but it will block your thread until the download is completed and is therefore not the preferred method, but I think it will answer your question:
private string Request(string url)
{
WebClient client = new WebClient();
return client.DownloadString(new Uri(url));
}

Related

Clearing out result from WebClient

I have the follow code section for a web client:
var client = new WebClient();
client.DownloadProgressChanged += (sender, args) =>
client_DownloadProgressChanged(sender, args, this.Context.ConnectionId);
client.DownloadDataCompleted += (sender, evt) =>
{
byte[] result = evt.Result;
aLongRunningTask(result);**
}
My problem is that the "aLongRunningTask" function needs to be initiated upon the completion of the downloaddata method, which is working fine, but since the file I receive is very large, I end up having a string in memory taking up a lot of memory space, that there is no need for since I only need byte[].
evt.Result is sadly a readonly property so I can not empty it, and I can not null the client, since I am running the aLongRunningTask.
Is there any way to either overwrite the evt.Result so it can be cleaned, or another way to get that memory usage emptied.
How about using using
like this
using(var client = new WebClient()){
//your logic
}

WebClient does not support concurrent I/O operations

How can I get this error from with in the DownloadStringCompleted Event? Doesn't that mean, it's finished? Is there another event I can fire this from?
I get this error extremely rarely, but once in a while it will happen on my WP7 phone. I have a web client that I fire over and over, and I fire it again from the completed event. Is this happening because there is still some stale connection open? Is there a way to prevent this 100%?
I have checked to see if there is a chance for the thread to walk over itself, but it is only fired from within the completed event.
How can I be sure, when the complete event is fired, the client is no longer isBusy? One suggestion was to add a while with a thread sleep while the client is busy.
Some pseudo code.
var client = new WebClient("URL 1");
client.CompletedEvent += CompletedEvent;
client.downloadasync();
void CompletedEvent(){
Dosomestuff;
client.downloadasync(); //This is where we break.
}
The WebClient only supports a single operations, it cannot download multiple files. You haven't shown your code, but my guess is that you are somehow firing a new request before the old is completed. My bet is that WebClient.IsBusy is true when you attempt to perform another fetch.
See the following thread:
wb.DownloadFileAsync throw "WebClient does not support concurrent I/O operations." exception
The only answer is to create a new webclient within the scope of the Completed Event. You can't set it to new since webclient is readonly. Creating a new client is the only solution. This allows the old client to complete in the background. This does have slight memory implications since you are creating a new instance instead of reusing an old. But the garbage collector should keep it clean if your scope is setup right.
Instead of using WebClient use HttpClient to do parallel HTTP calls. Below code shows how to download files.
HttpClient httpClient = new HttpClient();
var documentList=_documentManager.GetAllDocuments();
documentList.AsParallel().ForAll(doc =>
{
var responseResult= httpClient.GetAsync(doc.FileURLPath);
using (var memStream = responseResult.Result.Content.ReadAsStreamAsync().Result)
{
using (var fileStream =File.Create($"{filePath}\\{doc.FileName}"))
{
memStream.CopyTo(fileStream);
}
}
});
The solution, I found is to use multiple WebClient objects, so to modify your pseudocode example; try
var client = new WebClient("URL 1");
client.CompletedEvent += CompletedEvent;
client.downloadasync();
void CompletedEvent(){
Dosomestuff;
var client2 = new WebClient();
client2.downloadasync();
}
Create a new Web Client for each new request. Don't reuse an existing Web Client instance.
This allows the first request to complete before starting the new one. This is a standard way of creating new requests.
private async Void SyncParcelStatus(List<string> Urls)
{
try
{
foreach (var URL in WebhookUrls)
{
Task.Factory.StartNew(() => AsyncDownLoad(URL));
}
}
catch (Exception ex)
{
//log Exception
}
}
private async void AsyncDownLoad(string URL)
{
using (WebClient myWebClient = new WebClient())
{
try
{
Uri StringToUri = new Uri(URL);
myWebClient.DownloadStringAsync(StringToUri);
}
catch (Exception ex)
{
//log Exception
}
}
}

C# async persistent WebClient example

I need to make a simple http client in C# that must be asynchronous and must support a persistent connection to the server. So i'm trying to use the WebClient class, but i'm having some problems, my code is this:
void sendMessage()
{
ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(bypassAllCertificateStuff);
string loginRequest = #"{'IDENTIFIER':'patient1','PASSWORD':'asdasd','DEVICE_ID':'knt-01'}";
client = new WebClient();
// add event handlers for completed and progress changed
client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged);
client.UploadStringCompleted += new UploadStringCompletedEventHandler(client_UploadStringCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
// carry out the operation as normal
client.UploadStringAsync(new Uri("Https://192.168.1.100/PaLogin"), "POST", loginRequest);
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
Console.WriteLine("downloadProgressChanged");
}
void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
// Console.WriteLine(e.ProgressPercentage);
if (e.ProgressPercentage != 50)
{
Console.WriteLine("uploadProgressChanged");
}
}
void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
if (e.Result != null)
{
Console.WriteLine("Done");
}
}
The problem is that i should receive a response from the server, but neither the client_UploadStringCompleted nor client_DownloadProgressChanged callbacks are ever called.
The only thing I see on the console is: client_DownloadProgressChanged
So basically what i'm trying to do is:
1- I send some data to the server without closing the connection
2- I receive the server response but the connection must still be open when i have received it.
What am I missing?
Thank you. :-)
You are missing the whole HTTP protocol here.
HTTP is a stateless request-response protocol. HTTP 1.1 provides optional guidelines for keeping connections open purely for the sake of performance - although as for the request response paradigm, there is no change. [Yet I have seen many cases where client or server have decided not to respect it and closed the connection.] It also provides chunked encoding to facilitate streaming, but that is all it is as far as HTTP is concerned.
So basically in HTTP, client will wait for a reply (and keep connection open) until it receives a response or timeout. There is no way to change/better this behaviour.
NOW, back to you problem.
I think something is going wrong with connecting to the server so you need to use Fiddler to see what is happening. My hunch is it does not connect to server (firewall, server down, etc) since the certificate check is not even called.
Http server push mechanism can do this.
See this:
http://en.wikipedia.org/wiki/Comet_(programming))
c# client:
using (var client = new WebClient())
using (var reader = new StreamReader(client.OpenRead(uri), Encoding.UTF8, true))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
(che รจ quello che vi dicevo questo pomeriggio)

About HttpWebRequest's EndGetResponse

I'm using asynchronous calls for communication to my server. I written some component to collect all unauthorized requests and to resend them after user logs in. I written some test to produce 10 threads that are sending some requests without first being authorized. Than I wait for 20 seconds and do authorization and after that I wait for request to successfully finish. But problem appeared at EndGetResponse method which I call in my callback method. I done that this way:
public void InternalCallback(IAsyncResult result)
{
try
{
RequestState state = (RequestState)result.AsyncState;
IHttpWebRequest request = state.Request;
using (IHttpWebResponse response = responseGetter.GetResponse(request, result))
{
// ...
}
}
// ...
}
So, I made some custom class RequestState which has some higher level callbacks I need and it has request which I'll use to call EndGetResponse method. But this way I got error:
IAsyncResult object was not returned from the corresponding asynchronous method.
I changed this so I now have Request field in my callback class which I set before calling BeginGetResponse and I use that Request field when calling EndGetResponse in my callback.
public void InternalCallback(IAsyncResult result)
{
try
{
using (IHttpWebResponse response = responseGetter.GetResponse(this.Request, result))
{
// ...
}
}
// ...
}
Is this new solution valid one? Can you suggest is this good way to do this or how should I do this?

DownloadStringAsync() does not download the string asynchronously

Trying to implement downloadStringAsync() to prevent UI freezing for 10 seconds when downloading one byte of data. However, even though the download completes, it is freezing the UI just as if I used downloadString().
Here is my code:
public void loadHTML()
{
WebClient client = new WebClient();
// Specify that the DownloadStringCallback2 method gets called
// when the download completes.
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(loadHTMLCallback);
client.DownloadStringAsync(new Uri("http://www.example.com"));
return;
}
public void loadHTMLCallback(Object sender, DownloadStringCompletedEventArgs e)
{
// If the request was not canceled and did not throw
// an exception, display the resource.
if (!e.Cancelled && e.Error == null)
{
string result = (string)e.Result;
// Do cool stuff with result
}
}
Encountered the same problem, and found a solution.
Quite complex discussion here:
http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl
In short, the problem is web client is searching for proxy servers and hanging the app.
The following solution helps:
WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...

Categories

Resources