why my WebClient upload file code hangs? - c#

I am using VSTS 2008 + C# + .Net 3.5 + ASP.Net + IIS 7.0 to develop a Windows Forms application at client side to upload a file, and at server side I receive this file using an aspx file.
I find my client side application will hang after click the button to trigger upload event. Any ideas what is wrong and how to solve? Thanks!
Client side code,
public partial class Form1 : Form
{
private static WebClient client = new WebClient();
private static ManualResetEvent uploadLock = new ManualResetEvent(false);
private static void Upload()
{
try
{
Uri uri = new Uri("http://localhost/Default2.aspx");
String filename = #"C:\Test\1.dat";
client.Headers.Add("UserAgent", "TestAgent");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
client.UploadFileAsync(uri, "POST", filename);
uploadLock.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace.ToString());
}
}
public static void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
{
Console.WriteLine("Completed! ");
uploadLock.Set();
}
private static void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine("{0} uploaded {1} of {2} bytes. {3} % complete...",
(string)e.UserState,
e.BytesSent,
e.TotalBytesToSend,
e.ProgressPercentage);
// Console.WriteLine (e.ProgressPercentage);
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Upload();
}
}
Server side code:
protected void Page_Load(object sender, EventArgs e)
{
string agent = HttpContext.Current.Request.Headers["UserAgent"];
using (FileStream file = new FileStream(#"C:\Test\Agent.txt", FileMode.Append, FileAccess.Write))
{
byte[] buf = Encoding.UTF8.GetBytes(agent);
file.Write(buf, 0, buf.Length);
}
foreach (string f in Request.Files.AllKeys)
{
HttpPostedFile file = Request.Files[f];
file.SaveAs("C:\\Test\\UploadFile.dat");
}
}

you are waiting in the main windows events thread, so your GUI will be frozen.
Try this (using non static methods allows you to use the Control.Invoke method to run callbacks on the windows GUI thread and free this thread in order to redraw)
public partial class Form1 : Form
{
private static WebClient client = new WebClient();
private static ManualResetEvent uploadLock = new ManualResetEvent(false);
private void Upload()
{
try
{
Cursor=Cursors.Wait;
Uri uri = new Uri("http://localhost/Default2.aspx");
String filename = #"C:\Test\1.dat";
client.Headers.Add("UserAgent", "TestAgent");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
client.UploadFileAsync(uri, "POST", filename);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace.ToString());
this.Cursor=Cursors.Default;
this.Enabled=false;
}
}
public void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
{
// this callback will be invoked by the async upload handler on a ThreadPool thread, so we cannot touch anything GUI-related. For this we have to switch to the GUI thread using control.BeginInvoke
if(this.InvokeRequired)
{
// so this is called in the main GUI thread
this.BeginInvoke(new UploadFileCompletedEventHandler(UploadFileCompleteCallback); // beginInvoke frees up the threadpool thread faster. Invoke would wait for completion of the callback before returning.
}
else
{
Cursor=Cursors.Default;
this.enabled=true;
MessageBox.Show(this,"Upload done","Done");
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Upload();
}
}
}
And do the same thing in your progress (you could update a progressbar indicator for example).
Cheers,
Florian

Related

Run background worker in parallel with Webclient file download

I have a background worker used for running a time consuming sync operation with server and is working perfectly and UI is responsive during the operation
BackgroundWorker syncWorker = new BackgroundWorker();
syncWorker.WorkerReportsProgress = true;
syncWorker.DoWork += new DoWorkEventHandler(syncWorker_DoWork);
syncWorker.ProgressChanged += new ProgressChangedEventHandler(syncWorker_ProgressChanged);
syncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(syncWorker_RunWorkerCompleted);
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (xxxx item in actives)
{
target.ReportProgress(progress);
//time taking event running fine here..
}
target.ReportProgress(90);
}
private void syncWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lbl_progress.Text="Wait......";
}
private void syncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbl_progress.Text="DONE!..";
}
Now i have to do a file download operation and i am using Webclient to do it using the code
WebClient downloadClient = new WebClient();
downloadClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(downloadClient_DownloadProgressChanged);
downloadClient.DownloadFileCompleted += new AsyncCompletedEventHandler(downloadClient_DownloadFileCompleted);
downloadClient.DownloadFileAsync(new Uri(fileUrl), download_path);
void downloadClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
int progress_value = int.Parse(Math.Truncate(percentage).ToString());
progress_value = (progress_value < 5) ? 5 : (progress_value > 95) ? 95 : progress_value;
lblDownloadProgress.Content = string.Format("DOWNLOADING - {0}%", progress_value.ToString());
}
void downloadClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
string item = (string)e.UserState;
if (e.Error != null )
{
lblDownloadProgress.Content = "Unable to download.Try again.....";
lblDownloadProgress.Foreground = Brushes.Red;
}
else if (e.Cancelled)
{
//Do Nothing
}
else
{
lblDownloadProgress.Content ="DOWNLOADED..";
}
}
Now can i run these 2 things parallely ? Like run background worker while downlaoding the file??
if file downloading finished first wait till the completion of background worker
if background worker finished first wait till completion of download
Enable controls after both operations finished and keep UI responsive during the whole time
You can run 2 Background worker in parallel but if you need check the state of one of them you can check if the backgroundworker is busy(doing work or completed).
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
while( downloadClient.IsBusy)
{
Sleep(5000);
//waiting downloadClient worker to complete
}
//continue the work
}
look into this for check some trick you can do.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading;
namespace download_demo
{
class Program
{
static void Main(string[] args)
{
BackgroundWorker MyWorker = new BackgroundWorker();
MyWorker.DoWork += MyWorker_DoWork;
MyWorker.RunWorkerCompleted +=MyWorker_RunWorkerCompleted;
MyWorker.RunWorkerAsync();
Console.ReadKey();
}
private static void MyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("both job completed");
}
private static void MyWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread download = new Thread(DownloadJob);
download.Start();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(20);
Console.WriteLine("doing some job while downloading ");
}
Console.WriteLine("waiting the end of download......... ");
download.Join();
}
private static void DownloadJob(object path)
{
/// process download the path
///simulate 20 seconde of download
for(int i = 0;i<100;i++)
{
Thread.Sleep(50);
Console.WriteLine("downloaded :" + i + " Ko");
}
}
}
}

Download any file using windows form application with c#

I'll try to download file using this code.But file size is 0 KB.What is the correct and efficiency way to download the file.
private void DownloadFile()
{
using (WebClient Client = new WebClient())
{
Client.DownloadFileAsync(
new Uri("http://localhost/sn/userSelect.Designer.cs", UriKind.Absolute),
#"C:\xampp\htdocs\sn\test1.txt");
Client.Dispose();
}
}
Any one can give me the method for download the file over windows form program in C#.thanks
class Program
{
private static WebClient wc = new WebClient();
private static ManualResetEvent handle = new ManualResetEvent(true);
private static void Main(string[] args)
{
wc.DownloadProgressChanged += WcOnDownloadProgressChanged;
wc.DownloadFileCompleted += WcOnDownloadFileCompleted;
wc.DownloadFileAsync(new Uri(#"http://www.nattyware.com/bin/pixie.exe"), #"C:\\pixie.exe");
handle.WaitOne(); // wait for the async event to complete
}
private static void WcOnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null)
{
//async download completed successfully
}
handle.Set(); // in both the case let the void main() know that async event had finished so that i can quit
}
private static void WcOnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// handle the progres in case of async
//e.ProgressPercentage
}

Why can not read and write stream in thread

I want to process the http request in thread, the code as follow where the problem is that OutputStream (as noted in codes) can not be writen. When I put this process in main thread, it's no problem. Can you give me any advice?
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var server = new HttpServer();
try
{
server.EndPoint = new IPEndPoint(127.0.0.0, 80); //set webServer para
server.Start(); //start webServer
server.RequestReceived += server_RequestReceived; //register the event
}
catch (Exception ex)
{
return;
}
}
private void server_RequestReceived(object sender, HttpRequestEventArgs e)
{
var dataProcess = new Action<HttpRequestEventArgs>(DataProcess);
Dispatcher.BeginInvoke(dataProcess,e); //start thread
}
private void DataProcess(HttpRequestEventArgs e)
{
StreamReader sr = new StreamReader(#"c:\test.txt");
string text = sr.ReadToEnd();
using (var writer = new StreamWriter(e.Response.OutputStream)) //**Cannot write stream**
{
writer.Write(text);
}
sr.Close();
}
}
I think your request is being close before the new thread runs. What you can do is to execute the whole request in the new thread. Something like:
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var start = new Action<HttpRequestEventArgs>(Start);
Dispatcher.start(start,e); //start thread
}
private void Start(HttpRequestEventArgs e)
{
var server = new HttpServer();
server.EndPoint = new IPEndPoint(127.0.0.0, 80); //set webServer para
server.Start(); //start webServe
server.RequestReceived += server_RequestReceived; //register the event
}
private void server_RequestReceived(object sender, HttpRequestEventArgs e)
{
StreamReader sr = new StreamReader(#"c:\test.txt");
string text = sr.ReadToEnd();
using (var writer = new StreamWriter(e.Response.OutputStream)) //**Cannot write stream**
{
writer.Write(text);
}
sr.Close();
}
}
Most likley e.Response.OutputStream is write-only stream which contains response received from the server.
Depending on what you want to do you may either write to request stream or read from OutputStream.
Note: you are using some custom classes, so suggestion is based purely on method names.

download file from web in background in wp7

I'm writing an app in c# for wp7: 2 pages [mainpage, secondpage].
The application starts in mainpage, then the user can navigate to secondpage (using NavigationService.Navigate) in secondpage.
In secondpage WebClient downloads a file in the isolatedStorage.
My problem is that the download freezes when the user returns back to mainpage using the back key!
There is a way to do that in background so the user can navigate throw the pages freely?
Here is the code of the secondpage class (there is also a button with webClient.OpenReadAsync(uri) in the click event).
public partial class SecondPage : PhoneApplicationPage
{
WebClient webClient = new WebClient();
IsolatedStorageFile Storage = IsolatedStorageFile.GetUserStoreForApplication();
public SecondPage()
{
InitializeComponent();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
try
{
if (e.Result != null)
{
string fileName = "download.txt";
IsolatedStorageFileStream f = new IsolatedStorageFileStream(fileName, System.IO.FileMode.Create, Storage);
long fileNameLength = (long)e.Result.Length;
byte[] byteImage = new byte[fileNameLength];
e.Result.Read(byteImage, 0, byteImage.Length);
f.Write(byteImage, 0, byteImage.Length);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
try
{
if (ProgressDownload.Value <= ProgressDownload.Maximum)
{
ProgressDownload.Value = (double)e.ProgressPercentage;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Thanks
with the BackgroundWorker class i have this issue: when i call the webClient.OpenReadAsync the bw_doWork function (code is under) ends, because that call is async! so the bw reports the completeEvent.
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri("http://foo.com/asd.txt"));
}
Check out the Background Transfer APIs - sounds like this is exactly what you need to accomplish your requirements.

WebClient multi file Downloader error

im using the following code to download 50+ files from my webserver
private void button5_Click(object sender, EventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
//downloads
client.DownloadFileAsync(new Uri("http://www.site.com/file/loc.file"), #"c:\app\loc ");
client.DownloadFileAsync(new Uri("http://www.site.com/file/loc.file"), #"c:\app\loc ");
client.DownloadFileAsync(new Uri("http://www.site.com/file/loc.file"), #"c:\app\loc ");
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
progressBar.Value = int.Parse(Math.Truncate(percentage).ToString());
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Game Update Finished!");
}
im wanting to download 1 file at a time with a continuing progress bar iv got most of the coding done but when i hit the "Download" button i get the following error
WebClient does not support concurrent I/O operations.
what do i need to do?
Feel the difference:
It CAN download multiple files in parallel manner (by one stream per
one file).
But it CAN'T download one file using multiple streams.
Here is example (MainWindow contain one button 'Start' and five progress bars):
public partial class MainWindow : Window
{
private WebClient _webClient;
private ProgressBar[] _progressBars;
private int _index = 0;
public MainWindow()
{
InitializeComponent();
_progressBars = new [] {progressBar1, progressBar2, progressBar3, progressBar4, progressBar5};
ServicePointManager.DefaultConnectionLimit = 5;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Interlocked.Increment(ref _index);
if (_index > _progressBars.Length)
return;
_webClient = new WebClient();
_webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
_webClient.DownloadFileCompleted += WebClient_DownloadFileCompleted;
_webClient.DownloadFileAsync(new Uri("http://download.thinkbroadband.com/5MB.zip"),
System.IO.Path.GetTempFileName(),
_index);
}
private void WebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs args)
{
var index = (int) args.UserState;
_progressBars[index-1].Value = args.ProgressPercentage;
}
private void WebClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs args)
{
var index = (int)args.UserState;
MessageBox.Show(args.Error == null
? string.Format("Download #{0} completed!", index)
: string.Format("Download #{0} error!\n\n{1}", index, args.Error));
}
}
you are running multiple downloads in parallel with the same WebClient instance - the error tells you that this is NOT supported - you either:
use multiple instances of WebClient (one per parallel download)
OR
download one file after the other
Relevant information:
http://msdn.microsoft.com/en-us/library/system.net.webclient.aspx
http://msdn.microsoft.com/en-us/magazine/cc700359.aspx
WebClient does not support concurrent I/O operations (multiple downloads) per instance, so you need to create a separate WebClient instance for each download. You can still perform each download asynchronously and use the same event handlers.

Categories

Resources