Why UploadProgressChanged in WebClient.UploadFileAsync work not correctly? - c#

I'm upload file and get upload progress like this:
using (var wc = new WebClient())
{
wc.UploadProgressChanged += FileUploadProgressChanged;
wc.Headers.Add(HttpRequestHeader.ContentType, "image/png");
wc.UploadFileAsync(new Uri(url), filePath);
}
...
private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
ProgressBarUpload.Value = e.ProgressPercentage;
}
But after 50% e.ProgressPercentage return -441850 and then immediately returns 100. Why is this happening?

My solution:
private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
ProgressBarUpload.Value = e.BytesSent * 100 / e.TotalBytesToSend;
}
I also found two questions similar to this, but I have not managed to solve the problem. But it can be useful to others:
WebClient UploadFileAsync strange behaviour in progress reporting (cause of the problem - problems with authorization)
Uploading HTTP progress tracking (cause of the problem - the third-party application)
Note. Аfter downloading the file we receive a response from the server, it would be better to display the download file is 95% and the remaining 5% leave to display the response from the server. And in the end after a successful download and response from the server, we will be 100%.
PS: In the code, I did not show it, just say to those who might need it.

Related

Multiple processes in one button

First of all hello guys i just wanted to add button that downloads zip files from link and then unzips and i ran into problems i get this error:
"System.IO.IOException: 'The process cannot access the file
'C:\GTA\TEST.zip' because it is being used by another process.'"
It looks really simple but i can't solve it so i hope you guys help me. this is code:
private void button2_Click(object sender, EventArgs e)
{
string root = #"C:\GTA";
//this if directory doesn't exist
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
progressBar1.Value = 0;
WebClient webcl = new WebClient();
webcl.DownloadFileCompleted += Webcl_DownloadFileCompleted;
webcl.DownloadProgressChanged += Webcl_DownloadProgressChanged;
webcl.DownloadFileAsync(new Uri("https://download1474.mediafire.com/17r5hin4vceg/izkb8vk7pudg5g4/TEST.zip"), #"C:\GTA\TEST.zip");
string targetfolder = #"C:\GTA\UNZIPEDFolder";
string sourceZipFile = #"C:\GTA\TEST.zip";
ZipFile.ExtractToDirectory(sourceZipFile, targetfolder);
}
I'm no expert here, however you get the file asynchronosly without awaiting it.
DownloadFileAsync
So you make a call to extract the file while it's being downloaded.
You calling ExtractToDirectory before file will be actually downloaded, as file downloading is async. So, you need to await when downloading process will finish. To do so, you will need the following
make the whole event click handler async - private async void button2_Click(object sender, EventArgs e).
replace DownloadFileAsync which returns void and thus is not async/await-friendly with DownloadFileTaskAsync, which is awaitable.
Then you will able to await downloading with await webcl.DownloadFileTaskAsync(...args here...);
finally, you can remove DownloadFileCompleted subscription, as you may be sure that after await the file downloading is completed.
By the way, WebClient is considered as an old API and is not recommended for using in the new code. You may consider to switch to HttpClient.
To elaborate a bit on the two previous answers, you are in fact trying to unzip the file before you have downloaded it. You should change your code as follows:
private async void button2_Click(object sender, EventArgs e)
{
string root = #"C:\GTA";
//this if directory doesn't exist
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
progressBar1.Value = 0;
WebClient webcl = new WebClient();
webcl.DownloadFileCompleted += Webcl_DownloadFileCompleted;
webcl.DownloadProgressChanged += Webcl_DownloadProgressChanged;
await webcl.DownloadFileAsync(new Uri("https://download1474.mediafire.com/17r5hin4vceg/izkb8vk7pudg5g4/TEST.zip"), #"C:\GTA\TEST.zip");
string targetfolder = #"C:\GTA\UNZIPEDFolder";
string sourceZipFile = #"C:\GTA\TEST.zip";
ZipFile.ExtractToDirectory(sourceZipFile, targetfolder);
}
Note the async as well as the await before DownloadFileAsync().
Additionally, you might want to refactor that a bit and move the download / unzip part out of the Button Event Handler.

WebClient received more bytes than TotalBytesToReceive

I am running a Task on a list of remote files.
On every file I am using a WebClient and performing webClient.DownloadFileTaskAsync(...).
In the WebClient's DownloadProgressChanged handler I notice that the summing up e.BytesReceived until the completion of the task, gives a much higher result than the size I get by e.TotalBytesToReceive.
Sometimes the sum of the received bytes is exactly double of the size of the file, sometimes is much higher.
The size I get with e.TotalBytesToReceive is correct, is the same size i get with ResponseHeaders["Content-Length"] and checking the real file I am sure that the size is correct.
Why am I getting these values? Is there a header, or something, I have to remove in order to get the correct progress of the download?
The methods that download the files are
private async Task DownloadFiles(List<FileDetails> files)
{
await Task.WhenAll(files.Select(p => DownloadFileAsync(p)));
}
and
private async Task DownloadFileAsync(FileDetails f)
{
string localPath = #"C:\myDir";
try
{
using (WebClient webClient = new WebClient())
{
webClient.DownloadProgressChanged += MyHandler;
webClient.Credentials = CredentialCache.DefaultNetworkCredentials;
await webClient.DownloadFileTaskAsync(f.Path, localPath);
}
}
catch ()
{
}
}
And the code that handles the progress:
void MyHandler(object sender, DownloadProgressChangedEventArgs e)
{
//GlobalProgress and GlobalPercentage are global variables
//initialized at zero before the download task starts.
GlobalProgress += e.BytesReceived;
//UpdateDownloadTotal is the sum of the sizes of the
//files I have to download
GlobalPercentage = GlobalProgress * 100 / UpdateDownloadTotal;
}
If you check the example given for the BytesReceived property:
private static void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
// Displays the operation identifier, and the transfer progress.
Console.WriteLine("{0} downloaded {1} of {2} bytes. {3} % complete...",
(string)e.UserState,
e.BytesReceived,
e.TotalBytesToReceive,
e.ProgressPercentage);
}
Note that it's reporting the value simply as "transfer progress". I agree that the documentation could be more thorough here because it is slightly ambiguous, but for me (with this example1), it's clear that BytesReceived is "how many bytes have been received since we started this download", not "how many bytes have been received since this event was last raised".
As such, there's no need for you to accumulate the count - the accumulated count is what's already being given to you. And that's why you're getting overcounts - if its downloading 100k raises the event twice, once at the 50k mark and once at the 100k, as an example, your GlobalProgress will be 150k.
Agree with other comments though that you should just use ProgressPercentage to get the percentage.
1Since a message stating downloaded x of y bytes is practically useless if y is the expected total but x is just the delta since the message was last displayed.

WebClient DownloadString with TextChanged Event C#

I have an trouble in C# program which using php scripts to translate words and download the result string into TextBox.
My program has two TextBoxes
txtWord, txtTranslatedWord
and that's the simplified code
WebClient c = new WebClient();
private void txtWord_TextChanged(object sender, EventArgs e)
{
string response = c.DownloadString("http://example.com/Services/Translator/lang/EnglishToArabic.php?Word=" + txtWord.Text);
switch (response.ToLower())
{
case "not exist":
{
txtTranslatedWord.Text = "{Sorry but no translation for this word!}";
break;
}
default:
{
txtTranslatedWord.Text = response;
break;
}
}
}
The problem its when the text is changed the program lagging and looks like it would Stopped Working.
The program worked successfully but after so much lagging ,
especially if the writer is writing so fast.
I tried BackgroundWorker and make an delay like when user stop writing for 2 second then program start to translate but still lagging without any luck.
Is there any easy way to do this without problems?
Try to use asynchrony.
WebClient does not support concurrent I/O operations, so will be use HttpClient.
HttpClient client = new HttpClient();
private async void txtWord_TextChanged(object sender, EventArgs e)
{
var response = await client.GetStringAsync(
"http://example.com/Services/Translator/lang/EnglishToArabic.php?Word=" + txtWord.Text);
switch (response.ToLower())
{
case "not exist":
{
txtTranslatedWord.Text = "{Sorry but no translation for this word!}";
break;
}
default:
{
txtTranslatedWord.Text = response;
break;
}
}
}
Your problem is that every character your user types into the textbox results in a WebClient download that has to complete before the next keypress can be accepted. I'd suggest you do the following...
Create a timer that starts or restarts each time the user enters a character and that when expires disables the textbox and runs the search before re-enabling the textbox. You'd also do well to use an asynchronous WebClient call.

Sending huge base64 image to PHP via POST

I want to send a screenshot of my both screens to a PHP site via POST. It works fine, more or less.
Smaller images works fine, but bigger images causes problems.
I get this Visual Studio Error:
http://img.yuu.li/A34fPojk.png
I dont get any Error-Line and e.Result is empty too.
e.Error contains the message from the image.
This is my Code that may contains the error:
private static void UploadFileCallback(Object sender, UploadValuesCompletedEventArgs e)
{
if (e.Error != null)
{
FormHandler.manager.notify("Fehler!", "Folgender Fehler ist aufgetreten: \n" + e.Error, 4000);
return;
}
busy = false;
String result = System.Text.Encoding.Default.GetString(e.Result);
if (result.StartsWith("error"))
{
FormHandler.manager.notify("Fehler!", "Folgender Fehler ist aufgetreten: " + e.Result, 3000);
}
else
{
FormHandler.manager.notify("Fertig!", result, 3000);
Thread thread = new Thread(() => Clipboard.SetText(result));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
}
My php.ini:
http://img.yuu.li/mqvm7fPb
Maybe someone of you can tell my what am i doing wrong? Everything is working great with smaller images. So i thought maybe the php.ini is blocking something.
My image in base64 is around 251096 characters long.
Thank you :)
Okay I fixed it myself, thanks anyway :D
Problem was, I have installed Froxlor with FCGID.
FCGID blocked the request because the max request length is 131072.
I added this
FcgidMaxRequestLen 260000
in the file: /etc/apache2/mods-enabled/fcgid.conf

Calling a aspx page from windows service - Problem

I have a windows service that calls a page after a certain interval of time. The page in turn creates some reports.
The problem is that the service stops doing anything after 2-3 calls. as in it calls the page for 2-3 times and then does not do any work though it shows that the service is running...i am using timers in my service..
please can someone help me with a solution here
thank you
the code:(where t1 is my timer)
protected override void OnStart(string[] args)
{
GetRecords();
t1.Elapsed += new ElapsedEventHandler(OnElapsedTime);
t1.Interval = //SomeTimeInterval
t1.Enabled = true;
t1.Start();
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
try
{
GetRecords();
}
catch (Exception ex)
{
EventLog.WriteEntry(ex.Message);
}
}
public void GetRecords()
{
try
{
string ConnectionString = //Connection string from web.config
WebRequest Request = HttpWebRequest.Create(ConnectionString);
Request.Timeout = 100000000;
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
}
catch (Exception ex)
{
}
}
Well, what does the code look like? WebClient is the easiest way to query a page:
string result;
using (WebClient client = new WebClient()) {
result = client.DownloadString(address);
}
// do something with `result`
The timer code might also be glitchy if it is stalling...
It's possible that HttpWebRequest will restrict the number of concurrent HTTP requests to a specific page or server, as is generally proper HTTP client practice.
The fact that you're not properly disposing your objects most likely means you are maintaining 2 or 3 connections to a specific page, each with large timout value, and HttpWebRequest is queueing or ignoring your requests until the first few complete (die from a client or server timeout, most likely the server in this case).
Add a 'finally' clause and dispose of your objects properly!
I think you're missing something about disposing your objects like StreamReader, WebRequest, etc.. You should dispose your expensive objects after using them.
possibly the way you are requesting athe page is throwing an unnhandled exception which leaves the service in an inoperable state.
Yes, we need code.
Marc's advice worked for me, in the context of a service
Using WebClient worked reliably, where WebRequest timed out.
#jscharf explanation looks as good as any to me.

Categories