download file from web in background in wp7 - c#

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.

Related

c# webclient not timing out

Im trying to download files using extended WebClient with set timeout and I have a problem with the timeout (or what I think should cause timeout).
When I start the download with WebClient and receive some data, then disconnect wifi - my program hangs on the download without throwing any exception. How can I fix this?
EDIT: It actually throws exception but way later than it should (5 minutes vs 1 second which i set) - that is what Im trying to fix.
If you find anything else wrong with my code, please let me know too. Thank you for help
This is my extended class
class WebClientWithTimeout : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest w = base.GetWebRequest(address);
w.Timeout = 1000;
return w;
}
}
This is the download
using (WebClientWithTimeout wct = new WebClientWithTimeout())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
try
{
wct.DownloadFile("https://example.com", file);
}
catch (Exception e)
{
Console.WriteLine("Download: {0} failed with exception:{1} {2}", file, Environment.NewLine, e);
}
}
Try this, you can avoid UI blocking by this. Coming the WiFi when device connects to WiFi the download resumes.
//declare globally
DateTime lastDownloaded = DateTime.Now;
Timer t = new Timer();
WebClient wc = new WebClient();
//declarewherever you initiate download my case button click
private void button1_Click(object sender, EventArgs e)
{
wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
lastDownloaded = DateTime.Now;
t.Interval = 1000;
t.Tick += T_Tick;
wc.DownloadFileAsync(new Uri("https://github.com/google/google-api-dotnet-client/archive/master.zip"), #"C:\Users\chkri\AppData\Local\Temp\master.zip");
}
private void T_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - lastDownloaded).TotalMilliseconds > 1000)
{
wc.CancelAsync();
}
}
private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
lblProgress.Text = e.Error.Message;
}
}
private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
lastDownloaded = DateTime.Now;
lblProgress.Text = e.BytesReceived + "/" + e.TotalBytesToReceive;
}

How to download and run a .exe file c#

Before you flag this as a duplicate, yes there are questions just like this, i've looked at all of them and still couldn't get this working. I'm trying to code in a feature that downloads and runs a .exe file but it doesn't download, run or do anything. I even removed the try catches to find an error or error codes but I have non, so I have no idea where i'm going wrong, here is my code for it
public test_Configuration()
{
InitializeComponent();
}
Uri uri = new Uri("http://example.com/files/example.exe");
string filename = #"C:\Users\**\AppData\Local\Temp\example.exe";
private void button1_Click(object sender, EventArgs e)
{
try
{
if(File.Exists(filename))
{
File.Delete(filename);
}
else
{
WebClient wc = new WebClient();
wc.DownloadDataAsync(uri, filename);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
if (progressBar1.Value == progressBar1.Maximum)
{
progressBar1.Value = 0;
}
}
private void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if(e.Error == null)
{
MessageBox.Show("Download complete!, running exe", "Completed!");
Process.Start(filename);
}
else
{
MessageBox.Show("Unable to download exe, please check your connection", "Download failed!");
}
Change DownloadDataAsync to DownloadFileAsync.
wc.DownloadFileAsync(uri, filename);
This code helped me out quite a bit with updating a file, so I thought I would show my twist in the hopes that someone else out there has a similar requirement as me.
I needed this code to do the following when a button was clicked:
Grab a file from a sever and store it locally in AppData\Temp.
Keep my user up-to-date of install progress (an installer is downloaded).
If successfully downloaded (note the removal of the else after deleting old file check), launch "daInstaller.exe", whilst terminating the current running program.
And if said file already exist (i.e. the old "daIstaller.exe"), delete prior to copying new file to AppData\Temp.
Don't forget to keep the file names the same, else you'll be leaving more trash in that AppData\Temp folder.
private void button1_Click(object sender, EventArgs e)
{
Uri uri = new Uri("http://example.com/files/example.exe");
filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Temp/example.exe");
try
{
if (File.Exists(filename))
{
File.Delete(filename);
}
WebClient wc = new WebClient();
wc.DownloadFileAsync(uri, filename);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
if (progressBar1.Value == progressBar1.Maximum)
{
progressBar1.Value = 0;
}
}
private void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error == null)
{
Process.Start(filename);
Close();
Application.Exit();
}
else
{
MessageBox.Show("Unable to download exe, please check your connection", "Download failed!");
}
}

Windows Phone 8 FtpClient won't upload stream data previously used for issue with BitmapImage

I will try my best to explain the issue clearly. I'm using the code from
http://msdn.microsoft.com/en-us/magazine/dn385710.aspx
to create a photo sharing app. I am able to FTP images to my server fine. The issue I'm facing is when I tried to create the app to preview the picture and then FTP it. The FTP will still transfer the file, but the file size is always 0 size. I'm not sure if this is a bug or possibly me not disposing a certain object before FTP. Below are my codes:
Page 1
BitmapImage bitmapImage;
public PhotoPreview()
{
InitializeComponent();
btnYes.Tap += btnYes_Tap;
imgPreview.Width = G.getScreenWidth();
imgPreview.Height = G.getScreenHeight() - 250;
//windows phone 8 bug. When bitmap image is set...it blocks the FTP process thread. Will perform FTP on seperate page
previewPhoto();
}
void previewPhoto()
{
bitmapImage = new BitmapImage();
bitmapImage.SetSource(G.myStream);
imgPreview.Source = bitmapImage;
}
private void btnYes_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
disposeImage(bitmapImage);
NavigationService.Navigate(new Uri("/PhotoFTP.xaml", UriKind.Relative));
}
private void disposeImage(BitmapImage img)
{
if (img != null)
{
try
{
using (var ms = new MemoryStream(new byte[] { 0x0 }))
{
img = new BitmapImage();
img.SetSource(ms);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("ImageDispose FAILED " + e.Message);
}
}
}
Page 2
const string
IP_ADDRESS = "888.88.888",
FTP_USERNAME = "test",
FTP_PASSWORD = "test123"
;
string filename;
FtpClient ftpClient = null;
TestLogger logger = null;
public PhotoFTP()
{
InitializeComponent();
DateTime thisDay = DateTime.Today;
string timestamp = thisDay.Hour.ToString() + "_" + thisDay.Minute.ToString() + "_" + thisDay.Second.ToString();
filename = timestamp + ".jpg";
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Test_connect();
}
private async void Test_connect()
{
logger = TestLogger.GetDefault(this.Dispatcher);
lstLogs.ItemsSource = logger.Logs;
ftpClient = new FtpClient(IP_ADDRESS, this.Dispatcher);
ftpClient.FtpConnected += ftpClient_FtpConnected;
ftpClient.FtpFileUploadSucceeded += ftpClient_FtpFileUploadSucceeded;
ftpClient.FtpFileUploadFailed += ftpClient_FtpFileUploadFailed;
ftpClient.FtpAuthenticationSucceeded += ftpClient_FtpAuthenticationSucceeded;
ftpClient.FtpAuthenticationFailed += ftpClient_FtpAuthenticationFailed;
logger = TestLogger.GetDefault(this.Dispatcher);
await ftpClient.ConnectAsync();
logger.AddLog("Connecting...");
}
async void ftpClient_FtpConnected(object sender, EventArgs e)
{
logger.AddLog("Preparing...");
await (sender as FtpClient).AuthenticateAsync(FTP_USERNAME, FTP_PASSWORD);
}
private async void Test_upload()
{
logger.AddLog("Uploading photo...");
await ftpClient.UploadFileAsync(G.myStream, "username_timestamp.jpg");
}
void ftpClient_FtpAuthenticationFailed(object sender, EventArgs e)
{
logger.AddLog("Connection error.");
}
void ftpClient_FtpAuthenticationSucceeded(object sender, EventArgs e)
{
logger.AddLog("Connection established.");
Test_upload();
}
void ftpClient_FtpFileUploadFailed(object sender, FtpFileTransferFailedEventArgs e)
{
logger.AddLog("Failed.");
}
Boolean firstTime = true;
void ftpClient_FtpFileUploadSucceeded(object sender, FtpFileTransferEventArgs e)
{
logger.AddLog("Completed.");
}
If I comment out the line previewPhoto(); in page 1, it will FTP the file to my server fine. I believe the issue is the
bitmapImage.SetSource(G.myStream);
I've also tried to create two separate stream. One to preview the photo and the other to FTP. The result still resulted in 0 size file when FTP to the my server.
It's because the BitmapImage reads to the end of the stream, so the FtpClient has no data to read/upload.
Use Stream.Seek to reset the stream pointer back to the beginning.
G.myStream.Seek(0, SeekOrigin.Begin);

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.

why my WebClient upload file code hangs?

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

Categories

Resources