CSHARP running while every X seconds but until bool is true - c#

I would like to check updates from txt file on web server. and send a messagebox when there is version mismatch, I'm using this code and it works but I want it only to connect the server every 10 minutes and check the text file.
is there any option to do that?
maybe using another way to create this loop?
I also would like to send the messagebox only once
bool hasDisplayed = false;
private string UpdateCheckServer()
{
WebClient client = new WebClient();
Stream stream = client.OpenRead("http://localhost/update/update_version.txt");
StreamReader reader = new StreamReader(stream);
string serverversion = reader.ReadToEnd();
return serverversion;
}
private string UpdateCheckClient()
{
string ClientVersion = System.IO.File.ReadAllText("update_version.txt");
return ClientVersion;
}
private void UpdateCheckTimer()
{
while (!hasDisplayed)
{
if (starter.Enabled == true && UpdateCheckServer() == UpdateCheckClient())
{
//Nothing here
}
if (starter.Enabled == true && UpdateCheckServer() != UpdateCheckClient())
{
MessageBox.Show("not updated");
hasDisplayed = true;
}
}

An implementation based on timer can look like this:
private bool _equalVersion = true;
private System.Timers.Timer _timer = new System.Timers.Timer(1000 * 60 * 10); //millisecond * seconds * minutes
private void StartUpdateCheckTimer()
{
_timer.Elapsed += UpdateCheck;
_timer.Start();
}
private void UpdateCheck(object sender, ElapsedEventArgs e)
{
_timer.Stop();
_equalVersion = (UpdateCheckServer() == UpdateCheckClient());
if (!_equalVersion)
{
MessageBox.Show("not updated");
}
else
{
_timer.Start();
}
}
in this way you get a timer:
triggered each 10 minutes,
performing the check
notifying the version change (and stopping) or proceeding with the subsequent iterations
then you can add some more logic like for example reset of the check, more proper notification action (separating your check routine from the GUI part) and many more.
Another approach (as pointed out by #imsmn) can be to make your implementation System.Threading.Sleep based, but I'd suggest the first option based on timer.

After several tries and learning I managed to do that.
private string UpdateCheckServer()
{
WebClient client = new WebClient();
Stream stream = client.OpenRead("http://localhost/update/update_version.txt");
StreamReader reader = new StreamReader(stream);
string serverversion = reader.ReadToEnd();
return serverversion;
}
private string UpdateCheckClient()
{
string ClientVersion = System.IO.File.ReadAllText("update_version.txt");
return ClientVersion;
}
private void UpdateCheckTimer()
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 15000; // specify interval time as you want
t.Tick += new EventHandler(timer_Tick);
t.Start();
void timer_Tick(object sender, EventArgs e)
{
//Call method
if (starter.Enabled == true && UpdateCheckServer() != UpdateCheckClient())
{
t.Stop();
MessageBox.Show("not updated");
}
}
}

Related

How to fix download issues for some users using WebClient DownloadFileAsync?

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;
}

C# - Timer.Stop() isn't working

I make a call via client side to initiate the StopTickerTimer function which successfully calls the StopTickerTimer function but unfortunately doesn't actually stop the timer. The timer starts and works properly but I can't seem to understand why my timer isn't stopping. I've tried setting timer.Enabled = false. I've tried various solutions that I've found on here but nothing seems to work.
public Timer timer = new Timer();
private string jsonContents;
private string currentTickerPlaylist;
private int i = 0;
private List<string> playlistTickers;
public void StartTickerTimer(int seconds, string selectedPlaylist)
{
currentTickerPlaylist = selectedPlaylist;
InitPlaylistTickerTimer(seconds);
}
public void StopTickerTimer()
{
StopTimer();
}
private void InitPlaylistTickerTimer(int seconds)
{
timer.Elapsed += new ElapsedEventHandler(t_Tick);
timer.Interval = seconds * 1000;
timer.AutoReset = true;
timer.Start();
}
private void StopTimer()
{
timer.Stop();
}
private void t_Tick(object sender, EventArgs e)
{
SetPlaylistTickerSettings();
if (i >= playlistTickers.Count)
{
i = 0;
Payload ticker = new Payload
{
ticker = playlistTickers[i]
};
Payload ticker2 = new Payload
{
payload = ticker
};
var json = ServiceStack.Text.JsonSerializer.SerializeToString(ticker2);
PutToSingular("url", json);
i++;
}
else
{
Payload ticker = new Payload
{
ticker = playlistTickers[i]
};
Payload ticker2 = new Payload
{
payload = ticker
};
var json = ServiceStack.Text.JsonSerializer.SerializeToString(ticker2);
PutToSingular("url", json);
i++;
}
}
You started your timer, but you are not calling your "StopTimer" anywhere in the code...

Wait for DataReceived to fire without blocking the ui

I need to wait for the user to input data to the serialport reader and then process the data. However, using this code blocks the UI which is not what I want. Any ideas on how to make sure that data is received or a timeout has occured before continuing?
The reason I use
do
{
Thread.Sleep(1);
} while (...)
is because without it the code return indata before the user has time to change it.
I call ReadFromSerial from the main function and process the data there. If anything goes wrong I want it to return an empty string.
public string ReadFromSerial()
{
try
{
System.IO.Ports.SerialPort Serial1 = new System.IO.Ports.SerialPort("COM1", 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
var MessageBufferRequest = new byte[13] { ... };
int BufferLength = 13;
if (!Serial1.IsOpen)
{
Serial1.Open();
}
Serial1.Write(MessageBufferRequest, 0, BufferLength); //Activates the serialport reader
indata = "";
Stopwatch timer = new Stopwatch();
timer.Start();
Serial1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
do
{
Thread.Sleep(1);
} while (string.IsNullOrEmpty(indata) && timer.Elapsed.TotalSeconds < 10);
timer.Stop();
if (Serial1.IsOpen)
{
Serial1.Close();
}
return indata;
}
catch (Exception ex)
{
return "";
}
}
private static string indata;
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
try
{
SerialPort sp = (SerialPort)sender;
if (sp.BytesToRead > 0)
{
indata = sp.ReadExisting();
}
}
catch(InvalidOperationException)
{
;
}
}
This is where multi-threading, tasks, async programming and/or event handlers comes in handy. All of them offer something to help you get around stuff like this, depending on the types of objects you're using.
A good starting point in this case would be to run the whole receive loop as a separate thread, then send the received data back to the main thread in some fashion.
Here's the source of a form that does basically what yours does, but either as a Thread or a Task:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Button: starts Task version
private void button1_Click(object sender, EventArgs e)
{
StartReceiveTask();
}
// Button: starts Thread version
private void button2_Click(object sender, EventArgs e)
{
StartReceiveThread();
}
// Start the Receive loop as a Task
public void StartReceiveTask()
{
System.Threading.Tasks.Task.Run(() => receiveThreadFunc());
}
// Start the Receive loop as a Thread
public void StartReceiveThread()
{
var thd = new System.Threading.Thread(receiveThreadFunc);
thd.Start();
}
// Called when the Receive loop finishes
public void DataReceived(string data)
{
// do something with the data here
}
// The Receive loop, used by both Thread and Task forms.
public void receiveThreadFunc()
{
using (var serial1 = new System.IO.Ports.SerialPort("COM1", 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One))
{
// open serial port
if (!serial1.IsOpen)
serial1.Open();
// send init command
var initCommand = new byte[13];
serial1.Write(initCommand, 0, initCommand.Length);
// get start time
DateTime start = DateTime.Now;
// buffer for pushing received string data into
StringBuilder indata = new StringBuilder();
// loop until at most 10 seconds have passed
while ((DateTime.Now - start).TotalSeconds < 2)
{
if (serial1.BytesToRead > 0)
{
// allocate a buffer, up to 1K in length, to receive into
int blen = Math.Min(1024, serial1.BytesToRead);
byte[] buffer = new byte[blen];
// read chunks of data until none left
while (serial1.BytesToRead > 0)
{
int rc = serial1.Read(buffer, 0, blen);
// convert data from ASCII format to string and append to input buffer
indata.Append(Encoding.ASCII.GetString(buffer, 0, rc));
}
}
else
System.Threading.Thread.Sleep(25);
// check for EOL
if (indata.Length > 0 && indata.ToString().EndsWith("\r\n"))
break;
}
if (indata.Length > 0)
{
// post data to main thread, via Invoke if necessary:
string data = indata.ToString();
if (this.InvokeRequired)
this.Invoke(new Action(() => { DataReceived(data); }));
else
this.DataReceived(data);
}
}
}
}
I went with solution not to touch what I had already written. Instead I added these methods in my main function.
private void StartReceiveThread()
{
var thd = new System.Threading.Thread(receiveThreadFunc);
thd.Start();
}
private void receiveThreadFunc()
{
string str = Read.ReadFromSerial();
DataReceived(str);
}
private void DataReceived(string data)
{
//Process the data received
}

C# run same MessageBox 2 time in Timer Tick

I read time from php with C#. I have to show MessageBox before Logoff windows when the time is equal. But when I run program it show same MessageBox 2 time. I want to show MessageBox 1 time only before Logoff. I set Interval is 30,000. How to do it? This is my code
private void timer1_Tick(object sender, EventArgs e)
{
bool showingBox = false;
timer1.Start();
WebClient client = new WebClient();
Stream stream = client.OpenRead("http://172.22.22.20/time.php");
StreamReader reader = new StreamReader(stream);
String content = reader.ReadToEnd();
//textBox1.Text = content;
if (showingBox) return;
showingBox = true;
try
{
if (content == "08:00")
{
MessageBox.Show(new Form() { TopMost = true }, "11111"); // This will show 2 Message Box when time = 08.00
}
}
finally
{
showingBox = false;
}
if (content == "08:05")
{
ExitWindowsEx(4, 0);
}
timer1.Enabled = false;
}
}
}
I don't know if i understand your question right, but could it be that you start the timer twice ?
As far as i can see you do start the timer again in your timer_tick method
private void timer1_Tick(object sender, EventArgs e)
{
bool showingBox = false;
timer1.Start(); // <-- second time startet.
Why you using timer1.Start(); in timer1_Tick Event?
I remove timer1.Start() but it also show twice messagebox . I change the code like this flag = true; have to run before show message box . Now it work!!.
if (content == "10:09")
{
if (!flag)
{
flag = true;
MessageBox.Show(new Form() { TopMost = true }, "11111" +flag);
}
}

DownloadFileCompleted event doesn't fire inside while loop c# .net

I'm a bit confused why the event doesn't fire when the file has downloaded.
The file it self downloads perfectly fine.
I'm assuming there is some error in the way I am using this, in that the event doesn't fire inside a loop.
Thanks for any help anyone can give me
class DownloadQueue
{
public List<string[]> DownloadItems { get; set; }
public int CurrentDownloads;
public int DownloadInProgress;
string url = #"http://www.google.co.uk/intl/en_uk/images/logo.gif";
bool downloadComplete;
public DownloadQueue()
{
CurrentDownloads = 0;
DownloadItems = new List<string[]>();
Console.Write("new download queue made");
}
public void startDownloading(int maxSimulatiousDownloads)
{
downloadComplete = true;
DownloadInProgress = 0;
WebClient client = new WebClient();
client.DownloadFileCompleted +=
new AsyncCompletedEventHandler(this.downloadCompleteMethod);
while(DownloadInProgress != DownloadItems.Count )
{
if (downloadComplete == true)
{
downloadComplete = false;
client.DownloadFileAsync(new Uri(DownloadItems.ElementAt(DownloadInProgress).ElementAt(0).ToString()), DownloadItems.ElementAt(DownloadInProgress).ElementAt(1).ToString());
}
}
Console.Write("all downloads completed");
}
private void downloadCompleteMethod(object sender, AsyncCompletedEventArgs e)
{
downloadComplete = true;
DownloadInProgress++;
Console.Write("file Downloaded");
}
}
Where are you waiting for the DownloadFileAsync() call to complete? How about something like
manualResetEvent AllDone = new mre(false)
just before console.WriteLine
AllDone.WaitOne()
And in download complete
if (interlocked.decrement(ref downloadComplete) == 0) { AllDone.Set(); }
Most likely there is no time for the message to come. I suspect if you put an Application.DoEvents at the end of your loop, it would start firing the events. It is less than ideal to use it, but with the design you have, I can't think of a better way.

Categories

Resources