I have this code:
autoResetEvent = new AutoResetEvent(false);
clien = new WebClient();
clien.Encoding = Encoding.UTF8;
clien.DownloadDataCompleted += new DownloadDataCompletedEventHandler(clien_DownloadDataCompleted);
clien.DownloadDataAsync(new Uri("http://www.classoneequipment.com/"));
autoResetEvent.WaitOne();
void clien_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
Encoding enc = Encoding.UTF8;
myString = enc.GetString(e.Result);
autoResetEvent.Set();
}
When I run this code in a button click event - It works fine. but when I run the code from big class it gets stucked and don't arrive to the func: clien_DownloadDataCompleted.
You approach it all wrong. If you want to download 3000 or more pages you got to be a bit more efficient and not wait on the event from each download.
Implementation (just a rough draft, you have to complete it)
public class Downloader
{
ConcurrentQueue<Uri> _queue = new ConcurrentQueue<Uri>();
int _maxWorkers = 10;
long _currentWorkers = 0;
ManualResetEvent _completed;
public void Enqueue(Uri uri)
{
_queue.Enqueue(uri);
if (Interlocked.Read(_currentWorkers) < _maxWorkers)
{
// not very thread safe, but we just want to limit the workers
// within a reasonable limit. 1 or 2 more doesn't really matter.
Interlocked.Increment(_currentWorkers);
// yes, i'm a bit old fashioned.
TriggerJob();
}
}
private void TriggerJob()
{
Uri uri;
if (!_queue.TryDequeue(out uri))
{
Interlocked.Decrement(_currentWorkers);
return;
}
var client = new WebClient();
client.Encoding = Encoding.UTF8;
client.DownloadDataCompleted += DownloadDataCompleted;
client.DownloadDataAsync(uri);
}
private void DownloadDataCallback(object sender, DownloadDataCompletedEventArgs e)
{
try
{
// If the request was not canceled and did not throw
// an exception, display the resource.
if (!e.Cancelled && e.Error == null)
{
var args = new DownloadedEventArgs { uri = e.Uri, data = (byte[])e.result};
DownloadCompleted(this, args)
}
else
{
var args = new DownloadFailedEventArgs { uri = e.Uri, error = e.Error };
DownloadFailed(this, args);
}
}
catch (Exception err)
{
var args = new DownloadFailedEventArgs { uri = e.Uri, error = err };
DownloadFailed(this, args);
}
TriggerJob();
}
public event EventHandler<DownloadedEventArgs> DownloadCompleted = delegate{};
public event EventHandler<DownloadFailedEventArgs> DownloadFailed = delegate{};
}
public class DownloadedEventArgs
{
public Uri uri;
public byte[] data;
}
public class DownloadFailedEventArgs
{
public Uri uri;
public Exception error;
}
Usage:
var downloader = new Downloader();
downloader.Completed += (o,e) { Console.WriteLine("Whoohoho, completed: " + e.Uri); };
for (x = 1; x < 100000; x++)
{
downloader.Enqueue(new Uri("http://somewhere.com));
}
Related
I created a Windows Form Application in C# that users of my game modification can use to download updates automatically.
The 'Launcher', as I call it, uses WebClient to download the updates. But the first release of the mod is very big (2,7 GB zipped). The launcher works perfect for me and most users, but for some users the extraction of the zip file logs an error where the file is corrupted and not readable.
I searched already on stack, and it is possible that the file might be corrupted or truncated due to bad internet connection. But how do I build in a method that fix that problem?
//Start downloading file
using (WebClient webClient = new WebClient())
{
webClient.DownloadFileCompleted += new
AsyncCompletedEventHandler(Client_DownloadFileCompleted);
webClient.DownloadProgressChanged += new
DownloadProgressChangedEventHandler(Client_DownloadProgressChanged);
webClient.DownloadFileAsync(new Uri("http://www.dagovaxgames.com/api/downloads/+ patch.path), downloadPath);
}
private void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
//install the update
InstallUpdate();
}
private void InstallUpdate()
{
var file = currentPatchPath;
//get the size of the zip file
fileInfo = new FileInfo(file);
_fileSize = fileInfo.Length;
installBackgroundWorker = new BackgroundWorker();
installBackgroundWorker.DoWork += ExtractFile_DoWork;
installBackgroundWorker.ProgressChanged += ExtractFile_ProgressChanged;
installBackgroundWorker.RunWorkerCompleted += ExtractFile_RunWorkerCompleted;
installBackgroundWorker.WorkerReportsProgress = true;
installBackgroundWorker.RunWorkerAsync();
}
EDIT, just showing install code so that you know I am using a backgroundworker to extract the zip.
Common approach here is to download large file in small chunks and put them together on client after completion. Using this approach you can: 1. run few downloads in parallel and 2. in case of problem with network you don't have to download entire file again, just download incomplete chunks.
I faced a similar issue many years ago and created a subclass of WebClient that uses the DownloadProgressChanged event and a timer to abort downloads that get hung up and cancels the download smoother than the underlying internet transport layer does. The code also supports a callback to notify the calling code of progress. I found that sufficient to smoothly handle occasional hiccups downloading 1GB-ish files.
The idea of breaking your download into multiple pieces also has merit. You could leverage a library such as 7-Zip to both create the chunks and piece them back together (many compression libraries have that feature; I'm personally most familiar with 7-Zip).
Here's the code I wrote. Feel free to use and/or modify in any way that's helpful to you.
public class JWebClient : WebClient, IDisposable
{
public int Timeout { get; set; }
public int TimeUntilFirstByte { get; set; }
public int TimeBetweenProgressChanges { get; set; }
public long PreviousBytesReceived { get; private set; }
public long BytesNotNotified { get; private set; }
public string Error { get; private set; }
public bool HasError { get { return Error != null; } }
private bool firstByteReceived = false;
private bool success = true;
private bool cancelDueToError = false;
private EventWaitHandle asyncWait = new ManualResetEvent(false);
private Timer abortTimer = null;
private bool isDisposed = false;
const long ONE_MB = 1024 * 1024;
public delegate void PerMbHandler(long totalMb);
public delegate void TaggedPerMbHandler(string tag, long totalMb);
public event PerMbHandler NotifyMegabyteIncrement;
public event TaggedPerMbHandler NotifyTaggedMegabyteIncrement;
public JWebClient(int timeout = 60000, int timeUntilFirstByte = 30000, int timeBetweenProgressChanges = 15000)
{
this.Timeout = timeout;
this.TimeUntilFirstByte = timeUntilFirstByte;
this.TimeBetweenProgressChanges = timeBetweenProgressChanges;
this.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(MyWebClient_DownloadFileCompleted);
this.DownloadProgressChanged += new DownloadProgressChangedEventHandler(MyWebClient_DownloadProgressChanged);
abortTimer = new Timer(AbortDownload, null, TimeUntilFirstByte, System.Threading.Timeout.Infinite);
}
protected void OnNotifyMegabyteIncrement(long totalMb)
{
NotifyMegabyteIncrement?.Invoke(totalMb);
}
protected void OnNotifyTaggedMegabyteIncrement(string tag, long totalMb)
{
NotifyTaggedMegabyteIncrement?.Invoke(tag, totalMb);
}
void AbortDownload(object state)
{
cancelDueToError = true;
this.CancelAsync();
success = false;
Error = firstByteReceived ? "Download aborted due to >" + TimeBetweenProgressChanges + "ms between progress change updates." : "No data was received in " + TimeUntilFirstByte + "ms";
asyncWait.Set();
}
private object disposeLock = new object();
void MyWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
if (cancelDueToError || isDisposed) return;
long additionalBytesReceived = e.BytesReceived - PreviousBytesReceived;
PreviousBytesReceived = e.BytesReceived;
BytesNotNotified += additionalBytesReceived;
if (BytesNotNotified > ONE_MB)
{
OnNotifyMegabyteIncrement(e.BytesReceived);
OnNotifyTaggedMegabyteIncrement(Tag, e.BytesReceived);
BytesNotNotified = 0;
}
firstByteReceived = true;
try
{
lock (disposeLock)
{
if (!isDisposed) abortTimer.Change(TimeBetweenProgressChanges, System.Threading.Timeout.Infinite);
}
}
catch (ObjectDisposedException) { } // Some strange timing issue causes this to throw now and then
}
public string Tag { get; private set; }
public bool DownloadFileWithEvents(string url, string outputPath, string tag = null)
{
Tag = tag;
asyncWait.Reset();
Uri uri = new Uri(url);
this.DownloadFileAsync(uri, outputPath);
asyncWait.WaitOne();
return success;
}
void MyWebClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null) success = false;
if (cancelDueToError || isDisposed) return;
asyncWait.Set();
}
protected override WebRequest GetWebRequest(Uri address)
{
var result = base.GetWebRequest(address);
result.Timeout = this.Timeout;
return result;
}
void IDisposable.Dispose()
{
lock (disposeLock)
{
isDisposed = true;
if (asyncWait != null) asyncWait.Dispose();
if (abortTimer != null) abortTimer.Dispose();
base.Dispose();
}
}
}
I fixed it using a combination of a BackgroundWorker and downloading in small chunks (following up mtkachenko's solution). It also checks if the length of the downloaded file is the same as the one on the server. Using that, it can continue the download where the connection was interupted.
private void DownloadPatch(Patch patch){
//using background worker now!
downloadBackgroundWorker = new BackgroundWorker();
downloadBackgroundWorker.DoWork += (sender, e) => DownloadFile_DoWork(sender, e, patch);
downloadBackgroundWorker.ProgressChanged += DownloadFile_ProgressChanged;
downloadBackgroundWorker.RunWorkerCompleted += DownloadFile_RunWorkerCompleted;
downloadBackgroundWorker.WorkerReportsProgress = true;
downloadBackgroundWorker.RunWorkerAsync();
}
private void DownloadFile_DoWork(object sender, DoWorkEventArgs e, Patch patch)
{
string startupPath = Application.StartupPath;
string downloadPath = Path.Combine(Application.StartupPath, patch.path);
string path = ("http://www.dagovaxgames.com/api/downloads/" + patch.path);
long iFileSize = 0;
int iBufferSize = 1024;
iBufferSize *= 1000;
long iExistLen = 0;
System.IO.FileStream saveFileStream;
// Check if file exists. If true, then check amount of bytes
if (System.IO.File.Exists(downloadPath))
{
System.IO.FileInfo fINfo =
new System.IO.FileInfo(downloadPath);
iExistLen = fINfo.Length;
}
if (iExistLen > 0)
saveFileStream = new System.IO.FileStream(downloadPath,
System.IO.FileMode.Append, System.IO.FileAccess.Write,
System.IO.FileShare.ReadWrite);
else
saveFileStream = new System.IO.FileStream(downloadPath,
System.IO.FileMode.Create, System.IO.FileAccess.Write,
System.IO.FileShare.ReadWrite);
System.Net.HttpWebRequest hwRq;
System.Net.HttpWebResponse hwRes;
hwRq = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(path);
hwRq.AddRange((int)iExistLen);
System.IO.Stream smRespStream;
hwRes = (System.Net.HttpWebResponse)hwRq.GetResponse();
smRespStream = hwRes.GetResponseStream();
iFileSize = hwRes.ContentLength;
//using webclient to receive file size
WebClient webClient = new WebClient();
webClient.OpenRead(path);
long totalSizeBytes = Convert.ToInt64(webClient.ResponseHeaders["Content-Length"]);
int iByteSize;
byte[] downBuffer = new byte[iBufferSize];
while ((iByteSize = smRespStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
if (stopDownloadWorker == true)
{
autoDownloadReset.WaitOne();
}
saveFileStream.Write(downBuffer, 0, iByteSize);
long downloadedBytes = new System.IO.FileInfo(downloadPath).Length;
// Report progress, hint: sender is your worker
int percentage = Convert.ToInt32(100.0 / totalSizeBytes * downloadedBytes);
(sender as BackgroundWorker).ReportProgress(percentage, null);
}
}
As you can see, I report the progress, so that I have a working progress bar as well.
private void DownloadFile_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
statusTextLabel.Text = "Downloading updates for version " + currentDownloadingPatch + " (" + e.ProgressPercentage + "%)";
progressBar.Value = e.ProgressPercentage;
}
so what im actually trying to do is to comunicate with a DMX-Interface pluged to a PC/Host via an Xamarin Android App.
Allready got my Server running, works also with an console client i wrote first. So now I wrote the app,using the same Way as before, with a TCPClient and then writing the data via a stream.
Because I'm running the app in the emulator I use as IP 10.0.2.2 to connect, but I cannot establish a connection. The App crashes or I get a timeout exeption. Been trying and researching now for two days and now i'm desperate, so I attach my code here, hope anyone can help
Thanks, Johannes
App:
public class MainActivity : Activity
{
public Stream Stream;
TcpClient Client = null;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
//adding control elements from Resource.Layout.Main
Button at = FindViewById<Button>(Resource.Id.at);
Button enter = FindViewById<Button>(Resource.Id.enter);
Button thru = FindViewById<Button>(Resource.Id.thru);
Button all = FindViewById<Button>(Resource.Id.all);
Button one = FindViewById<Button>(Resource.Id.one);
Button two = FindViewById<Button>(Resource.Id.two);
Button three = FindViewById<Button>(Resource.Id.three);
Button four = FindViewById<Button>(Resource.Id.four);
Button five = FindViewById<Button>(Resource.Id.five);
Button six = FindViewById<Button>(Resource.Id.six);
Button seven = FindViewById<Button>(Resource.Id.seven);
Button eight = FindViewById<Button>(Resource.Id.eight);
Button nine = FindViewById<Button>(Resource.Id.nine);
Button zero = FindViewById<Button>(Resource.Id.zero);
Button comma = FindViewById<Button>(Resource.Id.comma);
Button connect = FindViewById<Button>(Resource.Id.connect);
Button clear = FindViewById<Button>(Resource.Id.clear);
at.Click += (o, e) =>
{
UpdateCmdLine("#");
};
clear.Click += (o, e) =>
{
FlushCmdLine();
};
enter.Click += (o, e) =>
{
TextView cmdLine = FindViewById<TextView>(Resource.Id.cmdLine);
ProcessData(cmdLine.Text);
FlushCmdLine();
};
thru.Click += (o, e) =>
{
UpdateCmdLine("/");
};
all.Click += (o, e) =>
{
UpdateCmdLine("#");
};
one.Click += (o, e) =>
{
UpdateCmdLine("1");
};
two.Click += (o, e) =>
{
UpdateCmdLine("2");
};
three.Click += (o, e) =>
{
UpdateCmdLine("3");
};
four.Click += (o, e) =>
{
UpdateCmdLine("4");
};
five.Click += (o, e) =>
{
UpdateCmdLine("5");
};
six.Click += (o, e) =>
{
UpdateCmdLine("6");
};
seven.Click += (o, e) =>
{
UpdateCmdLine("7");
};
eight.Click += (o, e) =>
{
UpdateCmdLine("8");
};
nine.Click += (o, e) =>
{
UpdateCmdLine("9");
};
zero.Click += (o, e) =>
{
UpdateCmdLine("0");
};
comma.Click += (o, e) =>
{
UpdateCmdLine(",");
};
connect.Click += (o, e) =>
{
try
{
TextView ip = FindViewById<TextView>(Resource.Id.ipField);
TextView port = FindViewById<TextView>(Resource.Id.portField);
TextView connectionStatus = FindViewById<TextView>(Resource.Id.connectedStatus);
Client = new TcpClient("10.0.2.2", 4711);
connectionStatus.Text = "Connected";
}
catch (System.Exception)
{
}
};
//implementing click functions
}
public void UpdateCmdLine(string update)
{
TextView cmdLine = FindViewById<TextView>(Resource.Id.cmdLine);
cmdLine.Text += update;
}
public void FlushCmdLine()
{
TextView cmdLine = FindViewById<TextView>(Resource.Id.cmdLine);
cmdLine.Text = "";
}
public int[] GetData(string channel, string value)
{
int[] data = new int[] {Int32.Parse(channel), Int32.Parse(value)};
return data;
}
public void SendData(int channel, int data)
{
if (Client.Connected)
{
Stream = Client.GetStream();
byte[] outgoingBytes = new byte[] {Convert.ToByte(channel),Convert.ToByte(data)};
Stream.Write(outgoingBytes,0,outgoingBytes.Length);
}
}
public void ProcessData(string cmdLine)
{
string[] divideStackedOps = cmdLine.Split(',');
foreach (string s in divideStackedOps)
{
if (s.Contains("/"))
{
string[] dividedThru = s.Split('/');
int channel1 = Int32.Parse(dividedThru[0]);
string[] dividedAt = dividedThru[1].Split('#');
int channel2 = Int32.Parse(dividedAt[0]);
int value = Int32.Parse(dividedAt[1]);
for (int e = channel2; e >= channel1; e--)
{
SendData(e, value);
}
}
else if (s.Contains("#"))
{
string[]dividedAll = s.Split('#');
int value = Int32.Parse(dividedAll[1]);
for (int e = 100; e > 0; e--)
{
SendData(e, value);
}
}
}
}
}
}
Server
public class DmxInterface
{
[DllImport("K8062D.dll")]
public static extern void StartDevice();
[DllImport("K8062D.dll")]
public static extern void SetData(int channel, int data);
[DllImport("K8062D.dll")]
public static extern void StopDevice();
[DllImport("K8062D.dll")]
public static extern void SetChannelCount(int count);
}
class Program
{
private static TcpListener Listener;
private static ArrayList Threads = new ArrayList();
public static Boolean ServerStopped;
public static void Main()
{
DmxInterface.StartDevice();
DmxInterface.SetChannelCount(10);
//Initialize Listener, start Listener
int port = 4711;
IPAddress ip = IPAddress.Parse("127.0.0.1");
Listener = new TcpListener(ip, port);
Listener.Start();
Console.WriteLine("Creating new listener on: "+ip+":"+port);
//Initialize MainServerThread, start MainServerThread
Console.WriteLine("Starting MainThread");
Thread mainThread = new Thread(Run);
mainThread.Start();
Console.WriteLine("Done");
while (!ServerStopped)
{
Console.WriteLine("Write 'stop' to stop Server...");
String cmd = "";
cmd = Console.ReadLine();
if (cmd.ToLower().Equals("stop"))
{
Console.WriteLine("stopping server");
ServerStopped = true;
}
else
{
Console.WriteLine("unknow command: " + cmd);
}
}
EndThreads(mainThread);
}
public static void EndThreads(Thread mainThread)
{
//stopping MainThread
mainThread.Abort();
Console.WriteLine("MainThread stopped");
//stopping all Threads
for (IEnumerator e = Threads.GetEnumerator(); e.MoveNext();)
{
//Getting next ServerThread
Console.WriteLine("Stopping the ServerThreads");
ServerThread serverThread = (ServerThread)e.Current;
//Stop it
serverThread.Stop = true;
while (serverThread.Running)
{
Thread.Sleep(1000);
}
}
//Stopping Listener
Listener.Stop();
Console.WriteLine("listener stopped");
Thread.Sleep(5000);
Console.Clear();
}
//opening a new ServerThread
public static void Run()
{
while (true)
{
Console.WriteLine("Listener waiting for connection wish");
//waiting for incoming connection wish
TcpClient client = Listener.AcceptTcpClient();
Threads.Add(new ServerThread(client));
}
}
}
class ServerThread
{
public bool Stop;
public bool Running;
private TcpClient client;
public ServerThread(TcpClient client)
{
this.client = client;
//starting new thread with run() function
Console.WriteLine("Starting new ServerThread");
new Thread(new ThreadStart(Run)).Start();
}
//threaded function
public void Run()
{
Stream stream = null;
Boolean gotstream = false;
Console.WriteLine("Reading incoming Data Stream");
Running = true;
while (!gotstream)
{
//making sure stream is not null to avoid exeption
if (client.GetStream() != null)
{
//getting stream, setting flag true
stream = client.GetStream();
gotstream = true;
}
}
Boolean loop = true;
byte[] incomingValues = new byte[] {255, 255};
Boolean gotData = false;
while (loop)
{
//checking if a remote host is still connected
if (client.Connected)
{
try
{
//reading Byte Array
stream.Read(incomingValues, 0, incomingValues.Length);
gotData = true;
}
catch (Exception e)
{
//catching exeptions
Console.WriteLine("Ooops, something wrent wrogn \n" + e);
loop = false;
}
if (gotData)
{
//converting bytes to int, sending DMX Values
int channel = Convert.ToInt32(incomingValues[0]);
int value = Convert.ToInt32(incomingValues[1]);
DmxInterface.SetData(channel, value);
Console.WriteLine("Received Data... \n Channel: " + channel + " Value: " + value);
}
}
else
{
//exiting loop if connection is lost
Console.WriteLine("connection lost");
Program.ServerStopped = true;
loop = false;
}
}
}
}
}
I have a function called getMessages that can be called by a Button click (using the RelayCommand trigger) or that is called in a timer every 15s.
The desired behavior is:
webservice > deserialize answer > system notification > updatelistview > insert localDB
But when the function is called by the timer the updatelistview is not done. Why does this happen if the function is the same and works perfectly in the button command?
CODE:
// Get messages for the logged in user
public async void getMessages()
{
try
{
List<FriendGetMessage> msg = new List<FriendGetMessage>();
var response = await CommunicationWebServices.GetCHAT("users/" + au.idUser + "/get", au.token);
if (response.StatusCode == HttpStatusCode.OK) // If there are messages for me.
{
var aux = await response.Content.ReadAsStringAsync();
IEnumerable<FriendGetMessage> result = JsonConvert.DeserializeObject<IEnumerable<FriendGetMessage>>(aux);
if (result != null)
{
foreach (var m in result)
{
msg.Add(m);
}
//MsgList=msg;
foreach (var f in Friends)
{
if (f.msg == null || f.msg.Count() == 0)
{
f.msg = new ObservableCollection<Messages>();
}
foreach (var mess in msg)
{
if (mess.idUser == f.idUser)
{
Messages mm = new Messages();
mm.received = mess.message;
mm.timestamp = "Received " + mess.serverTimestamp;
mm.align = "Right";
// Add to the friend list.
f.msg.Add(mm);
// Add to Local DB
InsertMessage(null, au.idUser.ToString(), f.idUser, mess.message, mess.serverTimestamp);
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
BalloonTipTitle = "New Message from " + f.name,
BalloonTipText = "Message: " + mess.message,
};
// Display for 5 seconds.
notification.ShowBalloonTip(5);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
}
}
}
counterChat = 1; // resets the counter
}
}
else {
counterChat = counterChat * 2;
}
//var sql = "select * from chat";
//var respo = GetFromDatabase(sql);
OnPropertyChanged("Friends");
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
Debug.WriteLine("{0} Exception caught.", e);
}
}
CODE TIMER:
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
ADDED - I've also tried this and didn't worked (it seems that is some kind of concurrency problem to the ObservableCollection called Friends (is a friendslist) each friend has an ObservableCollection of messages (is a chat))
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
Application.Current.Dispatcher.Invoke((Action)async delegate { await getMessages(); });
incChat = 0;
}
}
Best regards,
I think you need to make the timer handler be an async method as follows:
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
await getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
This way OnPropertyChanged("Friends") is guaranteed to fire after the work in getMessages is done.
The methods need to change to:
DispatcherTimer _timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
public async void timerchat_Tick(object sender, EventArgs e)
{
//...
await getMessages();
//...
}
public async Task getMessages()
{
try
{
// ... your code here
string result = await response.Content.ReadAsStringAsync();
// .... rest of your code
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
}
}
It is solved. The problem was in my ViewModels I was opening multiple threads and sometimes the right one would update the UI and sometimes no.
Thanks for all the answers.
How can I download file and show downloading progress by ProgressBar in window form app?
RestClient client = new RestClient("http://127.0.0.1/");
RestRequest request = new RestRequest("/test/{FileName}");
request.AddParameter("FileName", "testFile.abc", ParameterType.UrlSegment);
string path = #"C:/Users/[user]/Desktop/testFile.abc";
var fileForDownload = client.DownloadData(request);
fileForDownload.SaveAs(path);
if (File.Exists(#"C:/Users/[user]/Desktop/testFile.abc"))
{
MessageBox.Show("done");
}
I write somethink like this but I don't know what now?
I think a better alternative would be to override FileStream to get count of bytes written to file:
string tempFile = Path.Combine(Configuration.DownloadFolder, "TEST.DATA");
using (var writer = new HikFileStream(tempFile))
{
writer.Progress += (w, e) => {
#if DEBUG
Console.Write(string.Format("\rProgress: {0} / {1:P2}", writer.CurrentSize, ((double)writer.CurrentSize) / finalFileSize));
#endif
};
request.ResponseWriter = (responseStream) => responseStream.CopyTo(writer);
var response = client.DownloadData(request);
}
where HikFileStream is:
class HikFileStream : FileStream
{
public HikFileStream(string path)
: base(path, FileMode.Create, FileAccess.Write, FileShare.None)
{
}
public long CurrentSize { get; private set; }
public event EventHandler Progress;
public override void Write(byte[] array, int offset, int count)
{
base.Write(array, offset, count);
CurrentSize += count;
var h = Progress;
if (h != null)
h(this, EventArgs.Empty);//WARN: THIS SHOULD RETURNS ASAP!
}
}
Sorry but you can't, because there is no event handler object in RestClient to take status of download data.
Here is an alternative way to do it;
//...
timer1.Interval = 1000; // 1 sec interval.
timer1.Start();
RestClient client = new RestClient("http://127.0.0.1/")
{
Timeout = 10 * 1000 //10 sec timeout time.
};
RestRequest request = new RestRequest("/test/{FileName}");
request.AddParameter("FileName", "testFile.abc", ParameterType.UrlSegment);
string path = #"C:/Users/[user]/Desktop/testFile.abc";
var fileForDownload = client.DownloadData(request);
fileForDownload.SaveAs(path);
if (File.Exists(#"C:/Users/[user]/Desktop/testFile.abc"))
{
MessageBox.Show("done");
}
progressBar1.Value = 100;
timer1.Stop();
}
public void timer1_Tick(object sender, EventArgs e)
{
if (progressBar1.Value <= 100)
{
progressBar1.Value += 10;
}
if (progressBar1.Value >= 100)
{
progressBar1.Value = 0;
}
}
Change the name of "timer1" for naming-best-practices. Good luck...
I'm currently trying to do some webscraping using this code:
public static User registerUser()
{
User toreturn = new User();
string csrf;
WebBrowser webcontrol = new WebBrowser();
webcontrol.AllowNavigation = true;
webcontrol.ScriptErrorsSuppressed = true;
webcontrol.Navigate("https://example.com/signup");
webcontrol.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webcontrol_DocumentCompleted);
HtmlElementCollection forms = webcontrol.Document.GetElementById("csrf_token").GetElementsByTagName("value");
string tosend = forms[0].InnerText;
toreturn.apikey = tosend;
return toreturn;
}
private static void webcontrol_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
}
However, the entire variable webcontrol.Document is null, both before and after the event.
Any idea as to why this is? Hard to scrape when blind.
EDIT: Worth noting, obviously I need to use the values I get
OK
So now I have got it to load thanks to help below, but I can't get the threads to return the value..
public static User registerUser()
{
Uri test = new Uri("https://www.example.com/signup");
HtmlDocument testdoc = runBrowserThread(test);
string tosend = "test";
User user = new User();
user.apikey = tosend;
return user;
}
public static HtmlDocument runBrowserThread(Uri url)
{
HtmlDocument value = null;
var th = new Thread(() =>
{
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
value = br.Document;
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join(8000);
return value;
}
static void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var br = sender as WebBrowser;
if (br.Url == e.Url)
{
Console.WriteLine("Natigated to {0}", e.Url);
Console.WriteLine(br.Document.Body.InnerHtml);
System.Console.ReadLine();
Application.ExitThread(); // Stops the thread
}
}
The System.Console.WriteLine works - I see the HTML! Joy! (Although its cloudflare, but I should get whitelisted)
But the thread returns null..