I have a list of of StringsDouble called Messages.
The code for the class is below:
public class StringsDouble
{
public string Sender {get; set;}
public string Message {get; set;}
public DateTime Time {get; set;}
}
every time my app receives a new message. I update the List and i store the time of the latest message sent for the user sending that message.
what i want to do is, every 5 minutes the app should go through the list.
and for every item in the list it should get the time property and get the current system time , and check to see if the difference is more than 30 minutes. If it is, it should delete that item from the list.
How can i accomplish this?
I believe i need to use a background task, but how can i schedule it to run every 5 minutes?
You can use DispatcherTimer on UI thread:
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMinutes(5);
timer.Tick += (sender, e) =>
{
//...
};
timer.Start();
or ThreadPoolTimer on a background thread:
ThreadPoolTimer threadPoolTimer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
{
//...
}, TimeSpan.FromMinutes(5));
There is no way to run your backgroundtask every 5 minutes.
Maybe push notification can help you? It has a price as you can guess but you can send them any time, any frequency.
http://code.msdn.microsoft.com/windowsapps/Windows-8-Modern-Style-App-Samples
You can download these samples, there is a sample code for push notifications too.
This link (with code) seems to suggest that you can spread out the 2 seconds of CPU that is assigned to your app every 15 mins. You can therefore run some code in your background task more frequently than every 15 mins:
https://developer.qualcomm.com/blog/windows-8-background-tasks-part-3-make-most-cpu-usage-quota
Related
I have a method that detects beacons after each 30 seconds. The scenario is as follows:
The scan period of beacons is 60 seconds.
The waiting period before the next scan is 30 seconds.
The above settings have already been defined in the BeaconDectector class. Now to display the beacons scanned on my UI, I have the following:
private void Button_Clicked(object sender, EventArgs e)
{
bool start = true;
while (start) {
beaconsFound = StartDetection();
Device.BeginInvokeOnMainThread(() =>
{
listView.ItemsSource = beaconsFound;
});
}
}
The StartDetection contains the logic that take place every 30 seconds and the scan period is 60 seconds. How can I ensure that I don't miss any beacons to get displayed on my listview?
Please advise. Thank you.
You should definitely not use active waiting while(start) to manage this. A better solution would be a Timer. You can see the basics for this in this blogpost.
Furthermore, ensure you are not running any long running code on the UI thread (which is what Button_Clicked runs on). Ideally, your timer should fire each 30 seconds, start a new Task for the detection and use Device.BeginInvokeOnMainThread to update the list when appropriate.
I've got a Timer that's doing a 60 second countdown. When the ticks hit 60 seconds, it stops and disposes - no problem (I think). This is run in the context of a WebApi service. I need to be able to cancel the countdown from a UI, so I've exposed a method to handle this. Since the controller is transient (thanks Luaan) and, as Daniel points out, the app pool is not predictable, I need a way to send a "cancellable" countdown to clients. Ideas anyone?
[HttpGet]
public IHttpActionResult CancelCountdown()
{
// DOES NOTHING BECAUSE THERE'S A NEW INSTANCE OF THE CONTROLLER
timer.Stop();
timer.Dispose();
return Ok();
}
private void StartCountdown()
{
// MAY BE A BAD SOLUTION BECAUSE THE APP POOL MAY RECYCLE
timer.Interval = _timeIntervalInMilliseconds;
timer.Elapsed += BroadcastToClients;
timer.Start();
}
private void BroadcastToClients(object sender, EventArgs e)
{
_elapsed += 1;
if (_elapsed == _duration)//_duration is 60
{
timer.Stop();
timer.Dispose();
return;
}
_messageHub.Clients.All.shutdown(_elapsed);
}
It's kind of hard to provide an adequate solution without knowing what you're trying to accomplish with this, but i'll give it a shot.
As Luaan pointed out, controllers are designed to be essentially stateless, so you shouldn't put instance variable on them except for it's external dependencies, since each request creates a new instance of the controller class.
You could store the timer on a static dictionary, indexed by a GUID, and return the GUID on your controller and use it as the cancellation token.
Something like:
private static Dictionary<string,Timer> timers = new Dictionary<Guid,Timer>();
public Guid StartCountdown()
{
// MAY BE A BAD SOLUTION BECAUSE THE APP POOL MAY RECYCLE
timer.Interval = _timeIntervalInMilliseconds;
timer.Elapsed += BroadcastToClients;
var guid = Guid.NewGuid().ToString();
timers.Add(guid,timer);
timer.Start();
return guid;
}
public IHttpActionResult CancelCountdown(Guid cancelationToken)
{
//If the timer no longer exist or the user supplied a wrong token
if(!timers.HasKey(cancelationToken)) return;
var timer = timers[cancelationToken];
timer.Stop();
timer.Dispose();
timers.Remove(cancelationToken);
}
However this won't solve the problem with the AppPool recycling. For a more robust solution, instead of using a timer, you could store the start date and time of each countdown in a more permanent storage (say an SQL database, a NoSQL databse, a redis server or whatever), and have a running thread or global timer, or something like Hangfire, initialized on startup, that constantly checks your countdown storage. If enough time has passed to send a broadcast message you send it, and mark the countdown as finished. If a user wants to cancel the countdown, the controller will simply read the appropiate record, mark it as cancelled, and your running thread can ignore it.
If you go with this approach, you'll need to take into account some considerations:
If the timer interval is set too short you could have a perfomance bottleneck for having to access a permament storage too often. If the interval is too long, the countdown won't be too precise.
To alleviate this problem you could store the countdowns start time in permanent storage, in case the app pool resets and you need to restore them. And also have them stored in memory on a static variable for quicker access.
Please note that if you're working with a server farm instead of a single server, static variables won't be shared across instances.
I have a TextBox which tells the status of a running application (lets say notepad). If notepad is running Text of TextBox is running and not running for other case.
public string ProcessStatus
{
get
{
IsProcessRunning("Notepad.exe")
return "Running";
return "Not Running";
}
}
Now problem here is that view updates itself only once when it is launched. At that time if notepad is running it works fine. Now lets suppose I ran my application and notepad was not running then TextBox says not running. Now I launch notepad, now application is still saying not running as application has not updated the view. If I call notify of property changed event for the TextBox then it will say running. But I want here is that TextBox updates automatically.
The only solution what I am thinking right now is that I start a background process which keeps on updating ProcessStatus. But is this the right way? Is there any better way? Something like DirectoryWatcher for processes?
You could use a System.Windows.Threading.DispatcherTimer to check at regular intervals:
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(10000); // checks every 10 seconds
timer.Tick += Timer_Tick;
timer.Start();
...
private void Timer_Tick(object sender, EventArgs e)
{
// do your checks here
textbox.Text = ProcessStatus;
}
You can find out more about the DispatcherTimer class from the DispatcherTimer Class page at MSDN.
Why not use the timer class to periodically run ProcessStatus, you can define the interval.
On this other question Can I Get Notified When Some Process Starts? there are two answers on how you can get notified if a process (e.g. Notepad.exe) starts. Both are neither ideal nor simple, I would probably stick to polling as Sheridan and NSmeef suggested.
I'm trying to raise an event at a given time in my windows store app. Now I've done this in desktop apps countless times, and I've used System.Threading.Timer in the past and it has worked well, but that class is not available to windows store apps.
I have looked in the documentation and found a class called DispatchTimer and although it appears to be what I'm after, correct me if I'm wrong but the docs are lacking. But luckily it's pretty easy to use.
So I tried the DispatchTimer, but after using it, I'm not even sure this is what I should be using.
How can I watch for any given time and raise an event when that time is up (in a windows store app)? And do you know of any resources that do this in a metro app?
Use DispatcherTimer like this:
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(10) };
timer.Tick += OnTimerTick;
timer.Start();
private void OnTimerTick(object sender, object args)
{
// Do something with pickup here...
}
This will create a timer with intervals of 10 seconds.
The DispatcherTimer is the way to go. Notice that if you want your app to run in background you must declare that on the app manifest or use Background agents.
I use the following code in a asp.net website.
On application init i call InitializeTimer() once.
The goal of the code was to run DoWork() once every hour (1 time per hour) .
I also wanted the code to execute on different time every loop so i added the random part.
The result i got was werid , i can not find a explaination why is happens.
The code executed the function after 2hrs , then again after 2hrs , then after 3hrs , then after 2hrs , and 2hrs again.****
Can anybody explain the reason?
using System.Timers;
....
private static random = new Random();
....
public static void InitializeTimer()
{
tTimer = new Timer();
tTimer.AutoReset = true;
tTimer.Interval = TimeSpan.FromHours(1.0).TotalMilliseconds;
tTimer.Elapsed += new ElapsedEventHandler(ClassName1.tMailer_Elapsed);
tTimer.Start();
}
private static void tTimer_Elapsed(object sender, ElapsedEventArgs e)
{
tTimer.Interval += random.Next(-5, 5);
DoWork();
}
Update:
Please don't post "use windows service" , or "scheduled task".
My question is for the following code I'm not looking for better alternatives.
Also , during this test (10hrs) , website was with high traffic , iis pool did not restart!
Based on the following MSDN: (http://msdn.microsoft.com/en-us/library/system.timers.timer.interval.aspx)
If the interval is set after the Timer
has started, the count is reset. For
example, if you set the interval to 5
seconds and then set the Enabled
property to true, the count starts at
the time Enabled is set. If you reset
the interval to 10 seconds when count
is 3 seconds, the Elapsed event is
raised for the first time 13 seconds
after Enabled was set to true.
Is it possible that re-setting the interval in the elapsed function is the cause of the problem?
Meaning that when tTimer_Elapsed function is called the count is 1hr(min a few millisecond)
and my code "tTimer.Interval += random.Next(-5, 5);" is adding another full hour to the Interval?
ASP.NET applications will get shut down when not in use. If someone hits your site, and then no more hits, it can get shut down. Your timer won't fire.
For this type of maintenance work you want to use a windows scheduled task or windows service.
Check this out... Jeff Atwood actually discussed something similar. I guess it worked, but according to Jeff the site outgrew this method so they went to a dedicated task.
Since .net 4.5.2, there is a class called HostingEnvironment, it can do what you're asking, here is how to use:
https://blog.mariusschulz.com/2014/05/07/scheduling-background-jobs-from-an-asp-net-application-in-net-4-5-2
The HostingEnvironment.QueueBackgroundWorkItem method lets you
schedule small background work items. ASP.NET tracks these items and
prevents IIS from abruptly terminating the worker process until all
background work items have completed.
I second Sams suggestion of using windows scheduled task to hit a page every hour. I tried and tried to get mine to work and it sort of worked. I went to a scheduled task and it has never failed.