This question already has an answer here:
What would be a good way to Cancel long running IO/Network operation using Tasks?
(1 answer)
Closed 2 years ago.
I'm playing with TcpClient and when i use some Async operations they ignore the CancellationToken. After some reading, i know that it is intentionally and also knows that exists some ways to cancel awaits on Asyncs operations.
I just read next StackOverflow questions and articles that clarifies some points:
How to cancel a Task in await?
https://devblogs.microsoft.com/pfxteam/how-do-i-cancel-non-cancelable-async-operations/
Following previous articles, I could cancel NetworkStream.ReadAsync but that mechanisms doesn't work when i use them on NetworkStream.WriteAsync.
I have this code as minimal example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
CancellationTokenSource ctSource;
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
string http_resp = "";
var request_uri = new Uri("http://icanhazip.com");
//BIG FILE as postdata to test the WriteAsync (use one that you have on your disk)
string contents = File.ReadAllText(#"C:\Portables\4test.txt");
string post_data = contents;
ctSource = new CancellationTokenSource();
CancellationToken ct = ctSource.Token;
Task<string> task = HttpRequestAsync(post_data, request_uri, ct);
try
{
http_resp = await task;
}
catch
{
http_resp = "General error";
}
textBox1.Text = http_resp;
button1.Enabled = true;
}
private static async Task<string> HttpRequestAsync(string post_data, Uri request_uri, CancellationToken ct)
{
string result = string.Empty;
string http_method = "POST";
string post_content_type = "application/x-www-form-urlencoded";
var hostname = request_uri.Host;
var port = request_uri.Port;
var scheme = request_uri.Scheme;
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.SendTimeout = 15;
tcpClient.ReceiveTimeout = 15;
try
{
await tcpClient.ConnectAsync(hostname, port);
}
catch (Exception d1)
{
if (ct.IsCancellationRequested)
{
result = "Cancelation requested on ConnectAsync";
}
else
{
result = d1.Message + "\r\n" + d1.GetType().FullName + d1.StackTrace; ;
}
return result;
}
//Build HTTP headers
string reqString = "";
string header_host = "Host: " + hostname + "\r\n";
string header_close = "Connection: Close\r\n";
string basic_headers = "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0\r\n";
basic_headers += "Referer: https://www.google.com\r\n";
string header_post = "";
if (http_method == "POST")
{
string header_content_type = "";
header_content_type = "Content-type: " + post_content_type + "\r\n";
int content_length = 0;
content_length = post_data.Length;
string header_content_length = "Content-length: " + content_length + "\r\n";
header_post = header_content_type + header_content_length;
}
reqString = http_method + " " + request_uri.PathAndQuery + " " + "HTTP/1.1" + "\r\n" + header_host + basic_headers + header_close + header_post + "\r\n";
if (http_method == "POST")
{
reqString += post_data;
}
var header_bytes = Encoding.ASCII.GetBytes(reqString.ToString());
//Starting the I/O Network operations
using (NetworkStream tcp_stream = tcpClient.GetStream())
{
try
{
//HERE is where i have problems cancelling this await while WriteAsync is working.
await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct).WithCancellation(ct);
//await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct);
}
catch (Exception d2)
{
if (ct.IsCancellationRequested)
{
result = "Cancelation requested on WriteAsync";
}
else
{
result = d2.Message + "\r\n" + d2.GetType().FullName + d2.StackTrace;
}
return result;
}
using (var memory = new MemoryStream())
{
try
{
await tcp_stream.CopyToAsync(memory, 81920, ct);
}
catch (Exception d3)
{
if (ct.IsCancellationRequested)
{
result = "Request cancelled by user (on read)";
}
else
{
result = d3.Message + "\r\n" + d3.GetType().FullName + d3.StackTrace;
}
return result;
}
memory.Position = 0;
byte[] data = memory.ToArray();
result = Encoding.UTF8.GetString(data);
}
}
}
return result;
}
private void button2_Click(object sender, EventArgs e)
{
ctSource.Cancel();
}
}
It works good when i use it on ReadAsync:
await tcp_stream.ReadAsync(response, 0, response.Length, ct).WithCancellation(ct);
It doesn't work when i use it on WriteAsync:
await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct).WithCancellation(ct);
No error is returned, simply the await isn't cancelled. To be more clear i added a minimal example as a Visual Studio 2015 project that you can download here: https://github.com/Zeokat/minimal_ex/archive/master.zip
It also includes a file 4test.rar that you can decompress into a file of 39MB 4test.txt. I use this text file as post_data contents for test because is big enougth to call the Cancel action while the WriteAsync is running.
Can someone give me a hand on this? I spend some days trying to fix this but couldn't achieve a proper solution.
Thanks in advance.
Dont use .WithCancellation(ct) use only await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct).
cts = new CancellationTokenSource();
pass ct = cts.Token
in cancel_event() :
if(cts != null) cts.Cancel();
Related
I need to make a button that will stop downloading the file. For example, I clicked 1 time the download started and the second time it stopped.
private static async void Download()
{
foreach (string fileName in fileList)
{
string localDir = AppDomain.CurrentDomain.BaseDirectory;
localDir.Substring(0, localDir.Length - 1);
localDir += fileName;
long fileSize = await ftp.GetFileSizeAsync(fileName);
fileSize /= 1024;
form.progressBar1.Maximum = (int)fileSize;
var token = new CancellationToken();
Progress<FtpProgress> progress = new Progress<FtpProgress>(async loadedFile =>
{
if (loadedFile.Progress == 100)
{
form.progressBar1.Value = 0;
}
else
{
int x = (int)fileSize * Convert.ToInt32(loadedFile.Progress) / 100;
string value = loadedFile.TransferSpeedToString();
form.label1.Text = "Connection Speed: \n" + value;
form.progressBar1.Value = x;
}
});
await ftp.DownloadFileAsync(localDir, fileName, FtpLocalExists.Skip, FluentFTP.FtpVerify.Retry, progress, token);
}
}
First of all, you don't create directly a CancellationToken, you create a CancellationTokenSource and get it's Token.
Said that, you can imagine the use of that token, to allow to cancel the operation.
You can do something like this:
//At class level
CancellationTokenSource cancel = null;
private static async void Download()
{
if(cancel != null)
{
cancel.Cancel();
cancel.Dispose();
cancel = null;
return;
}
cancel = new CancellationTokenSource();
foreach (string fileName in fileList)
{
string localDir = AppDomain.CurrentDomain.BaseDirectory;
localDir.Substring(0, localDir.Length - 1);
localDir += fileName;
long fileSize = await ftp.GetFileSizeAsync(fileName);
fileSize /= 1024;
form.progressBar1.Maximum = (int)fileSize;
Progress<FtpProgress> progress = new Progress<FtpProgress>(async loadedFile =>
{
if (loadedFile.Progress == 100)
{
form.progressBar1.Value = 0;
cancel.Dispose();
cancel = null;
}
else
{
int x = (int)fileSize * Convert.ToInt32(loadedFile.Progress) / 100;
string value = loadedFile.TransferSpeedToString();
form.label1.Text = "Connection Speed: \n" + value;
form.progressBar1.Value = x;
}
});
try
{
await ftp.DownloadFileAsync(localDir, fileName, FtpLocalExists.Skip, FluentFTP.FtpVerify.Retry, progress, cancel.Token);
}
catch
{
//When the download is cancelled will throw an exception
//you can create a more specific handler
cancel.Dispose();
cancel = null;
}
}
}
I'm stuck with an App that is running on Windows 10 IoT Core. All Classes are working fine, except for the one that is creating a CSV File via JSON and is supposed to send it as an Email.
When the Code reaches the "ReturnToMainPage()" Function the Exception "System.Exception: The application called an interface that was marshalled for a different thread" is thrown.
The "funny" thing is, the Mail is being send and i recieve it but the Program won't switch to back to the Main Page as intendet after sending the Email.
Here is the Code of the Class:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using EASendMail;
namespace PratschZahlstation
{
public sealed partial class MailChoice : Page
{
private TextBlock _headerText;
private ComboBox _mailComboBox;
private Button _execute;
private Button _abort;
private EnDecode _coder = EnDecode.get_EnDecodeSingleton();
private string _mailto = null;
public MailChoice()
{
this.InitializeComponent();
Init();
}
private void Init()
{
_headerText = HeaderText;
_mailComboBox = MailAdresses;
_mailComboBox.Items.Add("---");
_mailComboBox.Items.Add("dummy#mail.com");
_mailComboBox.SelectedIndex = 0;
_execute = DoFunction;
_abort = DoExit;
}
private void DoFunction_Click(object sender, RoutedEventArgs e)
{
string selectedMail = this._mailComboBox.SelectedItem.ToString();
if(selectedMail == "---")
{
_headerText.Text = "Bitte eine Emailadresse aus der Liste auswählen.";
}
else
{
_headerText.Text = "CSV wird erstellt und per Mail versendet!";
_execute.IsEnabled = false;
_abort.IsEnabled = false;
_mailComboBox.IsEnabled = false;
_mailto = selectedMail;
DateTime date = DateTime.Now;
string strippedDate = date.ToString("yyyy-MM-dd") + " 00:00:01";
GetDataForCSV(strippedDate);
}
}
private async void GetDataForCSV(string dateAsString)
{
string correctedDate = "2019-07-01 00:00:01";//dateAsString;
string date = _coder.Base64Encode(correctedDate);
HttpClient _client = new HttpClient();
Uri _uri = new Uri("URI TO JSON-API");
_client.BaseAddress = _uri;
var request = new HttpRequestMessage(HttpMethod.Post, _uri);
var keyValues = new List<KeyValuePair<string, string>>();
keyValues.Add(new KeyValuePair<string, string>("mode", "10"));
keyValues.Add(new KeyValuePair<string, string>("date", date));
request.Content = new FormUrlEncodedContent(keyValues);
var response = await _client.SendAsync(request);
string sContent = await response.Content.ReadAsStringAsync();
keyValues = null;
if (sContent != null)
{
byte[] bytes = Encoding.UTF8.GetBytes(sContent);
string json = Encoding.UTF8.GetString(bytes);
if (!json.Contains("success"))
{
List<CSV_SQL_Json_Object> _Json = JsonConvert.DeserializeObject<List<CSV_SQL_Json_Object>>(json);
response.Dispose();
request.Dispose();
_client.Dispose();
if (_Json.Count == 0)
{
}
else
{
CreateCSV(_Json);
}
}
else
{
List<JSON_Status> _Json = JsonConvert.DeserializeObject<List<JSON_Status>>(json);
_headerText.Text = "Es ist der Folgender Fehler aufgetreten - Errorcode: \"" + _coder.Base64Decode(_Json[0].success) + "\"\r\nFehlermeldung: \"" + _coder.Base64Decode(_Json[0].message) + "\"";
_Json.Clear();
response.Dispose();
request.Dispose();
_client.Dispose();
}
}
}
private async void CreateCSV(List<CSV_SQL_Json_Object> contentForCSV)
{
DateTime date = DateTime.Now;
string csvName = date.ToString("yyyy-MM-dd") + ".csv";
StorageFolder storageFolder = KnownFolders.MusicLibrary;
StorageFile csvFile = await storageFolder.CreateFileAsync(csvName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
await FileIO.WriteTextAsync(csvFile, "Column1;Column2;Column3;Column4;\n");
foreach (var item in contentForCSV)
{
await FileIO.AppendTextAsync(csvFile, _coder.Base64Decode(item.Object1) + ";" + _coder.aesDecrypt(_coder.Base64Decode(item.Object2)) + ";" + _coder.aesDecrypt(_coder.Base64Decode(item.Object3)) + ";" + _coder.aesDecrypt(_coder.Base64Decode(item.Object4)) + "\n");
}
SendEmail(_mailto, csvName);
}
private async void SendEmail(string mailto, string csvName)
{
try
{
SmtpMail oMail = new SmtpMail("Mail");
SmtpClient oSmtp = new SmtpClient();
oMail.From = new MailAddress("noreply#dummy.com");
oMail.To.Add(new MailAddress(mailto));
oMail.Subject = "The Subject";
oMail.HtmlBody = "<font size=5>MailText</font>";
StorageFile file = await KnownFolders.MusicLibrary.GetFileAsync(csvName).AsTask().ConfigureAwait(false);
string attfile = file.Path;
Attachment oAttachment = await oMail.AddAttachmentAsync(attfile);
SmtpServer oServer = new SmtpServer("mail.dummy.com");
oServer.User = "dummyuser";
oServer.Password = "dummypass";
oServer.Port = 587;
oServer.ConnectType = SmtpConnectType.ConnectSSLAuto;
await oSmtp.SendMailAsync(oServer, oMail);
}
catch (Exception ex)
{
string error = ex.ToString();
_abort.IsEnabled = true;
}
ReturnToMainPage(); //This is where the Error Happens
}
private void ReturnToMainPage()
{
this.Frame.Navigate(typeof(MainPage));
}
private void DoExit_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(MainPage));
}
}
}
This could be an Threading issue. Navigation is only possible on the main-Thread.
You may want to try to marshal the call in:
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
);
Source:
The application called an interface that was marshalled for a different thread - Windows Store App
Like Tobonaut said, you can use the Dispatcher.RunAsync to call the Navigation, it worked.
But your problem may not be this.
I copied your code and reproduced your problem and found that you have problems with the calls to read and write files:
// Your code
StorageFile csvFile = await storageFolder.CreateFileAsync(csvName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
StorageFile file = await KnownFolders.MusicLibrary.GetFileAsync(csvName).AsTask().ConfigureAwait(false);
The Navigation will be work if you delete the .AsTask().ConfigureAwait(false).
Best regards.
I'm trying to download a list of links of images to my server (Up to 40 links) using foreach.
In my case sometimes the link exists but I don't know why it's going to catch and cancel the download of the next link. Maybe it needs to wait for a little? because when I debug the app I see that the link was the application skipped and went to catch was available but sometimes it's open after few seconds in my browser so the response time from the server I trying to download sometimes need more time to load and open the link.
string newPath = "~/data/" + model.PostID + "/" + name + "/";
//test1 is a list of links
foreach (var item1 in test1)
{
HttpWebRequest request = WebRequest.Create(item1) as HttpWebRequest; request.Method = "HEAD";
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
var webClient = new WebClient();
string path = newPath + i + ".jpg";
webClient.DownloadFileAsync(new Uri(item1), Server.MapPath(path));
string newlinks = "https://example.com/data/" + chapter.PostID + "/" + name + "/" + i + ".jpg";
allimages = allimages + newlinks + ',';
response.Close();
i++;
}
}
catch
{
break;
}
}
Now my main goal is to fix this issue but as I saw in debugging:
The Images Links I'm trying to download exists
Sometimes Need More Time to response
So How I can fix this ? when download cancel and a link exists, what I should do?
you can use this example:
class WebClientUtility : WebClient
{
public int Timeout { get; set; }
public WebClientUtility() : this(60000) { }
public WebClientUtility(int timeout)
{
this.Timeout = timeout;
}
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address);
if (request != null)
{
request.Timeout = Timeout;
}
return request;
}
}
//
public class DownloadHelper : IDisposable
{
private WebClientUtility _webClient;
private string _downloadUrl;
private string _savePath;
private int _retryCount;
public DownloadHelper(string downloadUrl, string savePath)
{
_savePath = savePath;
_downloadUrl = downloadUrl;
_webClient = new WebClientUtility();
_webClient.DownloadFileCompleted += ClientOnDownloadFileCompleted;
}
public void StartDownload()
{
_webClient.DownloadFileAsync(new Uri(_downloadUrl), _savePath);
}
private void ClientOnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
_retryCount++;
if (_retryCount < 3)
{
_webClient.DownloadFileAsync(new Uri(_downloadUrl), _savePath);
}
else
{
Console.WriteLine(e.Error.Message);
}
}
else
{
_retryCount = 0;
Console.WriteLine($"successfully download: # {_downloadUrl} to # {_savePath}");
}
}
public void Dispose()
{
_webClient.Dispose();
}
}
//
class Program
{
private static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
var downloadUrl = $#"https://example.com/mag-{i}.pdf";
var savePath = $#"D:\DownloadFile\FileName{i}.pdf";
DownloadHelper downloadHelper = new DownloadHelper(downloadUrl, savePath);
downloadHelper.StartDownload();
}
Console.ReadLine();
}
}
to fix timeout problem you can create a derived class and set the timeout property of the base WebRequest class and
for retry you can use the DownloadFileCompleted event of the WebClient and implement your retry pattern there
You're using the async version of 'DownloadFileAsync'. However you're not awaiting the call, that leaves a mess with unpredicted behaviour.
Make your method async and then use this:
await webClient.DownloadFileAsync(new Uri(item1), Server.MapPath(path));
This Solved my case:
await Task.Run(() =>
{
webClient.DownloadFileAsync(new Uri(item1), Server.MapPath(path));
});
In my app i have a list with links.
public List<string> Urls ()
{
var list = new List<string>();
list.Add("http://example.com/image.jpg");
list.Add("http://example.com/image1.jpg");
list.Add("http://example.com/image2.jpg");
return list;
}
I use a webclient for downloading.
private void downloadAlbum_Click(object sender, EventArgs e)
{
foreach (var link in Urls())
{
using (var wc = new WebClient())
{
wc.DownloadFile(link.ToString(),fileName);
}
}
}
But, my winform is lagging. While WebClient do this work.
Maybe anyone have a example for async function with multiple download and show current progress in progress bar?
Update.
I have async await for one file
private void Downloader(string link, string filepath)
{
using (WebClient wc = new WebClient())
{
wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
wc.DownloadFileAsync(new Uri(link), filepath);
}
}
private void Wc_DownloadProgressChanged(object sender,
DownloadProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void Wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
progressBar.Value = 0;
if (e.Cancelled)
{
MessageBox.Show("Canceled", "Message", MessageBoxButtons.OK,MessageBoxIcon.Error);
return;
}
if (e.Error != null)
{
MessageBox.Show("Somethings wrong, check your internet","Message", MessageBoxButtons.OK,MessageBoxIcon.Error);
return;
}
MessageBox.Show("Download is done!", "Message",MessageBoxButtons.OK,MessageBoxIcon.Information);
}
Progress value:
Tuple<DateTime, long, long> DownloadingProgress = new Tuple<DateTime, long, long>(DateTime.MinValue, 0, 0);
DownloadingProgress = new Tuple<DateTime, long, long>(DateTime.Now, 0, 0);
Before you start to download use this:
Wc.DownloadProgressChanged += DownloadProgressChanged; //when you start download
And here DownloadProgressChanged
private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs downloadProgressChangedEventArgs)
{
DownloadingProgress = new Tuple<DateTime, long, long>(DateTime.Now, downloadProgressChangedEventArgs.TotalBytesToReceive, downloadProgressChangedEventArgs.BytesReceived);
}
So you can see the progress with percent:
Console.WriteLine("Downloading: " + ((DownloadingProgress.Item3 * 100) / DownloadingProgress.Item2) + "% - " + DownloadingProgress.Item2 + " / " + DownloadingProgress.Item3);
I suggest you to use System.Net.Http.HttpClient instead of WebClient because when you tried to download files asynchronously best practice to use System.Net.Http.HttpClient.
I found idea behind this in link : HttpClientDownload
For downloading list of files you have to use:
private async void DownloadFiles(List<Uri> urls)
{
try
{
Progress<double> progress = new Progress<double>();
foreach (Uri uri in urls)
{
if (!client.isProcessCancel)
{
//Gets download progress - pgrBarDowload is our Progress Bar
progress.ProgressChanged += (sender, value) => pgrBarDowload.Value = (int)value;
}
var cancellationToken = new CancellationTokenSource();
writeOperation("Downloading File: " + uri.OriginalString);
//Set files in download queue
client.isProcessCancel = false;
await client.DownloadFileAsync(uri.OriginalString, progress, cancellationToken.Token, directoryPath);
}
}
catch (Exception ex)
{
writeOperation(ex.Message);
}
}
This method will download provided files asynchronously:
HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(30);
public async Task DownloadFileAsync(string url, IProgress<double> progress, CancellationToken token, string fileDirectoryPath)
{
using (HttpResponseMessage response = httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result)
{
response.EnsureSuccessStatusCode();
//Get total content length
var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
var canReportProgress = total != -1 && progress != null;
using (Stream contentStream = await response.Content.ReadAsStreamAsync(), fileStream = new FileStream(fileDirectoryPath + url.Substring(url.LastIndexOf('/') + 1), FileMode.Create, FileAccess.Write, FileShare.ReadWrite, 8192, true))
{
var totalRead = 0L;
var totalReads = 0L;
var buffer = new byte[8192];
var isMoreToRead = true;
do
{
var read = await contentStream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0)
{
isMoreToRead = false;
}
else
{
await fileStream.WriteAsync(buffer, 0, read);
totalRead += read;
totalReads += 1;
if (totalReads % 2000 == 0 || canReportProgress)
{
//Check if operation is cancelled by user
if (!isProcessCancel)
{
progress.Report((totalRead * 1d) / (total * 1d) * 100);
}
else
{
progress.Report(100);
}
}
}
}
while (isMoreToRead);
}
}
}
Note: Progress Bar will show progress for each file individually. This code is tested for Large Media files too. You can also set Progress for all files together by Calculating files size before download start.
I have created small demonstration in c# WinForm application related to Files download, Download progress and File Operations. Please follow below link: enter link description here
Please feel free comment any suggestions or doubts.
I am programming an application for downloading articles from an SQL Database on the internet. I have programmed the Website for managing the articles. Now I'm downloading the article List in gzip Format and then I decompress them to a xml-File. When I'm done I want to insert the articles to the mobile phone. This works great. Now I want to add an progress Bar to see the state of the insertion. I tried with Threading but this doesn't work. I'm posting some pieces of code from my application and also the progressUpdate methods.
private void btn_send_Click(object sender, EventArgs e)
{
label1.Text = "Download started";
string ArticlesURL = "URLTOSITE";
InvokeAsync(ArticlesURL);
}
private void InvokeAsync(string URL)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.AllowWriteStreamBuffering = true;
allDone.Reset();
request.BeginGetRequestStream(new AsyncCallback(ReadArticlesCallback), request);
allDone.WaitOne();
request.BeginGetResponse(new AsyncCallback(ResponseArticlesCallback), request);
}
private static void ReadArticlesCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
//End the operation.
Stream postSream = request.EndGetRequestStream(asynchronousResult);
string postData = "articles=test";
//Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//Write to the request stream.
postSream.Write(byteArray, 0, postData.Length);
postSream.Close();
allDone.Set();
}
private static void ResponseArticlesCallback(IAsyncResult asynchronousResult)
{
Form1 f = new Form1();
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse resp = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = resp.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
nbrArticles = Convert.ToInt16(responseString);
// Close the stream object.
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse.
resp.Close();
f.truncate_articles();
f.get_articles();
}
private void get_articles()
{
string url = "URLTOSITE";
int startPoint = 0;
DownloadZipFile((object)startPoint, url);
DecompressFile();
getXmlAndInsertInDB();
}
private void getXmlAndInsertInDB()
{
int total = nbrArticles;
int count = total / 100; //How much articles are 1 percent
int i = 0;
String barcode = "";
String name = "";
bool state = false;
XmlTextReader reader = new XmlTextReader("Program Files\\SmartDeviceProject1\\articles.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: //The node is an element
while (reader.MoveToNextAttribute()) //Get the attributes like barcode, lastname, firstname, pincode
switch (reader.Name)
{
case "barcode":
barcode = reader.Value.ToString();
state = false;
break;
case "name":
name = reader.Value.ToString();
state = true;
break;
}
break;
}
if (state == true)
{
cmd.CommandText = "INSERT INTO articles(barcode, name) " +
"VALUES('" + barcode + "','" + name + "');";
cmd.ExecuteNonQuery();
state = false;
i++;
if (i == count)
{
Thread t = new Thread(new ThreadStart(this.incrementProgressBar));
t.Start();
//incrementProgressBar();
i = 0;
}
}
}
reader.Close();
}
private void updateProgressBarMethod(int progress)
{
if (progressBar1.InvokeRequired)
{
//It was called from a non UI thread so we create a delegate
//and have the UI Thread call this method again
UpdateProgressBar = new UpdateProgressBarDelegate(updateProgressBarMethod);
this.Invoke(UpdateProgressBar, progress);
}
else
{
//Called from the UI Thread OK to update
//update your progress bar here
progressBar1.Value += progress;
}
}
private void incrementProgressBar()
{
//Call the method to update progress Bar on UI thread
//we do not need a delegate here that will be taken care of
//in the method
updateProgressBarMethod(1);
Application.DoEvents();
}
I think the problem is that I am using Callbacks. I have read that the Callbacks are also starting Threads. So I think the problem is there but I can't solve it.
I've found another very good site for threading with mobile applications: Updating the User Interface from a Worker Thread
Now with the new code, the debugger stops always at the same piece of code without any notification or exception :( Here is my new code:
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
this.Invoke(new EventHandler(WorkerUpdate)); //The Debugger stops here!
i = 0;
step++;
Thread.Sleep(700);
}
public void WorkerUpdate(object sender, EventArgs e)
{
this.lbl_percent.Text = this.info_percent;
this.lbl_percent.Update();
this.progressBar1.Value = step;
this.progressBar1.Update();
}
The Debugger stops at: this.Invoke(new EventHandler(WorkerUpdate));
I would suggest using the Background worker class. I had a similar problem and implemented the Background worker and it fixed my problem. Hopefully it will fix yours also
http://www.dotnetperls.com/backgroundworker
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
I found another thread discussing this and thought it would help:
Is there a BackgroundWorker replacement for .NET Compact Framework 3.5?
Your code will always hang at this point:
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
this.Invoke(new EventHandler(WorkerUpdate)); //The Debugger stops here!
i = 0;
step++;
Thread.Sleep(700);
}
Make these changes:
public delegate void MethodInvoker(); // this is not defined in CF
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
object sender = null; // make this whatever you want/need
EventArgs e = new EventArgs();
if (this.InvokeRequired) {
MethodInvoker mi = delegate { WorkerUpdate(sender, e); } };
this.BeginInvoke(mi);
} else {
WorkerUpdate(sender, e);
}
i = 0;
step++;
// Thread.Sleep(700); Why is this here?
}
This should prevent those obnoxious freezes.