I've found a couple of Stack Overflow questions along with a couple of blog posts that already touch on this topic, but unfortunately none of them are meeting my needs. I'll just start with some sample code to show what I'd like to accomplish.
using System;
using System.Security.Permissions;
using System.Threading.Tasks;
using System.Windows.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MyApp
{
[TestClass]
public class MyTests
{
private int _value;
[TestMethod]
public async Task TimerTest()
{
_value = 0;
var timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(10)};
timer.Tick += IncrementValue;
timer.Start();
await Task.Delay(15);
DispatcherUtils.DoEvents();
Assert.AreNotEqual(0, _value);
}
private void IncrementValue(object sender, EventArgs e)
{
_value++;
}
}
internal class DispatcherUtils
{
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
}
This code works fine if, instead of using a DispatcherTimer, I use an ordinary Timer. But DispatcherTimer never fires. What am I missing? What do I need to get it to fire?
It's best if you can avoid DispatcherTimer in your system under test and use an abstraction instead (Rx has a nice one called IScheduler). This kind of abstraction allows you to explicitly control the flow of time in your unit tests, rather than making your tests conditional on CPU timings.
But if you are just interested in unit testing for now, then you'll need to create an STA thread that does message pumping and have a proper Dispatcher installed. All "run this code on the dispatcher" operations just wrap a delegate in a Win32 message, and if you don't have a Win32 message pumping loop in a Dispatcher (before creating the timer), then those messages won't be processed.
The easiest way to do this is to use WpfContext from here:
[TestMethod]
public async Task TimerTest()
{
await WpfContext.Run(() =>
{
_value = 0;
var timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(10)};
timer.Tick += IncrementValue;
timer.Start();
await Task.Delay(15);
Assert.AreNotEqual(0, _value);
});
}
Again, this kind of approach is substandard because it depends on timings. So if your antivirus gets upset and decides to inspect your unit test, it can spuriously fail. An abstraction like IScheduler enables reliable unit tests.
Related
I have created a Windows Service that will be calling out to some COM components, so I tagged [STAThread] to the Main function. However, when the timer fires, it reports MTA and the COM calls fail. How can I fix this?
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
namespace MyMonitorService
{
public class MyMonitor : ServiceBase
{
#region Members
private System.Timers.Timer timer = new System.Timers.Timer();
#endregion
#region Construction
public MyMonitor ()
{
this.timer.Interval = 10000; // set for 10 seconds
this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
}
#endregion
private void timer_Elapsed (object sender, ElapsedEventArgs e)
{
EventLog.WriteEntry("MyMonitor", String.Format("Thread Model: {0}", Thread.CurrentThread.GetApartmentState().ToString()), EventLogEntryType.Information);
}
#region Service Start/Stop
[STAThread]
public static void Main ()
{
ServiceBase.Run(new MyMonitor());
}
protected override void OnStart (string[] args)
{
EventLog.WriteEntry("MyMonitor", "My Monitor Service Started", EventLogEntryType.Information);
this.timer.Enabled = true;
}
protected override void OnStop ()
{
EventLog.WriteEntry("MyMonitor", "My Monitor Service Stopped", EventLogEntryType.Information);
this.timer.Enabled = false;
}
#endregion
}
}
Services are run by the windows service hosting system, which runs using MTA threads. You can't control this. You have to create a new Thread and set its ApartmentState to STA, and do your work on this thread.
Here's a class that extends ServiceBase that does this:
public partial class Service1 : ServiceBase
{
private System.Timers.Timer timer;
public Service1()
{
InitializeComponent();
timer = new System.Timers.Timer();
this.timer.Interval = 10000; // set for 10 seconds
this.timer.Elapsed += new System.Timers.ElapsedEventHandler(Tick);
}
protected override void OnStart(string[] args)
{
timer.Start();
}
private void Tick(object sender, ElapsedEventArgs e)
{
// create a thread, give it the worker, let it go
// is collected when done (not IDisposable)
var thread = new Thread(WorkerMethod);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
OnStop(); // kill the timer
}
private void WorkerMethod(object state)
{
// do your work here in an STA thread
}
protected override void OnStop()
{
timer.Stop();
timer.Dispose();
}
}
Note this code doesn't actually stop the service, it stops the timer. There could be lots of work still being done on multiple threads. For instance, if your work consisted of running multiple queries off a large database you may end up crashing because you have too many threads running at the same time.
In a situation like this, I'd create a set number of STA threads (maybe 2x the number of cores to start off with) which monitor a thread-safe queue for work items. The timer tick event would be responsible for loading that queue with the work needing done.
It all depends on what you're actually doing every ten seconds, whether or not it should be completed the next time the timer ticks, what you should do in this situation, etc etc.
That cannot work in a service, the thread that calls your Main() method was already started by the service manager. You'll need to create a separate thread that is initialized with Thread.SetApartmentState() and pumps a message loop.
Setting the STAThread attribute will not work on a service. It's not being handled the same way as an application, so this will get ignored.
My recommendation would be to manually make a separate thread for your service, set its apartment state, and move everything into it. This way, you can set the thread to STA correctly.
However, there will be another issue here - you'll have to rework the way your service works. You can't just use a System.Threading.Timer instance for timing - it runs on a separate thread, which will not be STA. When its elapsed event fires, you'll be working on a different, non-STA thread.
Instead of doing your work in the timer event, you'll probably want to do your main work in the thread you create explicitly. You can have a reset event in that thread which blocks, and have your timer "set" it to allow your logic to run in the STA thread.
Looking at a similar example: http://www.aspfree.com/c/a/C-Sharp/Creating-a-Windows-Service-with-C-Sharp-introduction/1/
What if your main is...
[STAThread]
public static void Main ()
{
MyMonitor m = new MyMonitor();
m.Start();
}
and move your timer start / stop out of the events...
public void Start() { this.timer.Enabled = true;}
public void Stop() { this.timer.Enabled = false;}
protected override void OnStart (string[] args)
{
EventLog.WriteEntry("MyMonitor", "My Monitor Service Started", EventLogEntryType.Information);
}
protected override void OnStop ()
{
EventLog.WriteEntry("MyMonitor", "My Monitor Service Stopped", EventLogEntryType.Information);
}
This reports that it is using STA. It is based on Will's suggestion and http://en.csharp-online.net/Creating_a_.NET_Windows_Service%E2%80%94Alternative_1:_Use_a_Separate_Thread
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
namespace MyMonitorService
{
internal class MyMonitorThreaded : ServiceBase
{
private Boolean bServiceStarted = false;
private Thread threadWorker;
private void WorkLoop ()
{
while (this.bServiceStarted)
{
EventLog.WriteEntry("MyMonitor", String.Format("Thread Model: {0}", Thread.CurrentThread.GetApartmentState().ToString()), EventLogEntryType.Information);
if (this.bServiceStarted)
Thread.Sleep(new TimeSpan(0, 0, 10));
}
Thread.CurrentThread.Abort();
}
#region Service Start/Stop
protected override void OnStart (String[] args)
{
this.threadWorker = new Thread(WorkLoop);
this.threadWorker.SetApartmentState(ApartmentState.STA);
this.bServiceStarted = true;
this.threadWorker.Start();
}
protected override void OnStop ()
{
this.bServiceStarted = false;
this.threadWorker.Join(new TimeSpan(0, 2, 0));
}
#endregion
}
}
I am trying to create a Windows Service that executes a job on a timer and has graceful shutdown. I've used various questions/answers on here to come up with the code below. It works but I want to make sure it's the most correct and elegant solution. And I have specific questions too (after code).
This is the main service class.
using System;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
namespace MyService
{
public class MyService : ServiceBase
{
CancellationTokenSource cancellationTokenSource;
System.Timers.Timer serviceTimer;
Task workTask;
public static void Main(string[] args)
{
if (!Environment.UserInteractive)
{
Run(new MyService());
}
}
protected override void OnStart(string[] args)
{
cancellationTokenSource = new CancellationTokenSource();
serviceTimer = new System.Timers.Timer(30000);
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
}
protected override void OnStop()
{
try
{
serviceTimer.Stop();
cancellationTokenSource.Cancel();
if (workTask != null)
{
workTask.Wait(10000);
}
}
finally
{
serviceTimer.Dispose();
serviceTimer = null;
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
}
private void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
serviceTimer.Stop();
workTask = Task.Run(() => StartWorkMethod()).ContinueWith(WorkCompleted);
}
private void WorkCompleted(Task completedTask)
{
workTask = null;
serviceTimer.Start();
}
private void StartWorkMethod()
{
Work work = new Work(cancellationTokenSource.Token);
work.StartWork();
}
}
}
This is the class that performs the (currently simulated) work.
using System.Threading;
namespace MyService
{
public class Work
{
CancellationToken cancellationToken;
public Work(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public void StartWork()
{
for (int i = 0; i < 4; i++)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
Thread.Sleep(10000);
}
}
}
}
The service works and runs all tasks without blocking the handler threads. If the service is stopped, the OnStop method will wait for the task's current block of work to complete for a certain period of time before stopping anyways (thanks Ian of Oz!).
Here are my specific questions:
To prevent the service from stopping immediately and waiting for the current block to complete, I am using the working variable and a while loop to wait for the Work class to complete and the bool to be set to false. Is this the best way to handle this? Already answered by Ian of Oz.
I also want to have a "feature" where if the current block is taking too long to complete, the OnStop method will only wait a certain amount of time before exiting anyways. What is the best way to implement that? Already answerd by Ian of Oz.
I've tried to make sure I handle all threading issues with my code. Is there anything I missed or that might cause trouble later with this implementation?
Also some notes to avoid any confusion:
Service install code is not included, I am using an installer to install the service.
The timer controls the time between executions so that there aren't overlapping executions if the previous execution takes longer; this is why the timer stops before starting the work and restarts after.
I've seen where the Main method is sometimes placed in it's own file, but mostly where the executable is also the installer; in this case it would only simplify this file by the Main method itself.
Edited to incorporate suggestion from Ian of Oz.
After leaving the scope the thread TimerTest.exe!TimerTest.TimeClass.Callback(object state) is still running.
What is best practise to avoid such running threads?
IDisposable the class TimerClass?
Add a destructor?
Implement a method to dispose the timer?
Small Sample:
using System;
using System.Threading;
namespace TimerTest
{
internal class Program
{
private static void Main(string[] args)
{
// just a scope
{
var timerClass = new TimerClass(1);
}
Console.ReadKey();
}
}
internal class TimerClass
{
private Timer timer;
public TimerClass(int i)
{
this.timer = new Timer(Callback, i, 500, 1000);
}
private void Callback(object state)
{
Console.Out.WriteLine("Timer: " + state);
}
}
}
As you start the timer in the main thread the actually starts a new thread in the threadpool.
If you will implement IDispoable and create the timer class with using like:
(using var timerClass = new TimerClass(1))
{
your code here....
}
In the dispose method you will need to remove refence from the timer so the GC will collect this object as there will be no more refernces to this object.
The best way for my opnion is to use the IDispoe with the using...
You also can clean refenrce from timer in the callback method when you reach the amount of hits.
About the weak refernce - i am not sure that this situation fit to the defintion
My design is illustrated by below example. Having a while true loop doing something and notifying by an event that it has done something to all subscribers. My application should not continue its execution before its done notifying all subscribers, where this works as long as someone do not put a async void on the callback.
If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.
Its 3th party plugins that register themeself and subscribe to the event, so I have no control over if they put a async void. Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Test
{
public event EventHandler Event;
public void DoneSomething()
{
if (Event != null)
Event(this,EventArgs.Empty);
}
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
test.Event += test_Event;
test.Event +=test_Event2;
while(true)
{
test.DoneSomething();
Thread.Sleep(1000);
}
}
private static void test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
}
static async void test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}
}
}
If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.
There is really no way to avoid this. Even if you were to somehow "know" that the subscriber wasn't implemented via async/await, you still couldn't guarantee that the caller didn't build some form of asynchronous "operation" in place.
For example, a completely normal void method could put all of its work into a Task.Run call.
My application should not continue its execution before its done notifying all subscribers
Your current version does follow this contract. You're notifying the subscribers synchronously - if a subscriber does something asynchronously in response to that notification, that is something outside of your control.
Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.
Note that this is actually possible. For example, you can rewrite your above as:
public class Program
{
public static void Main()
{
var test = new Test();
test.Event += test_Event;
test.Event +=test_Event2;
test.DoneSomethingAsync().Wait();
}
}
public delegate Task CustomEvent(object sender, EventArgs e);
private static Task test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
return Task.FromResult(false);
}
static async Task test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}
public class Test
{
public event CustomEvent Event;
public async Task DoneSomethingAsync()
{
var handler = this.Event;
if (handler != null)
{
var tasks = handler.GetInvocationList().Cast<CustomEvent>().Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
}
You can also rewrite this using event add/remove, as suggested by svick:
public class Test
{
private List<CustomEvent> events = new List<CustomEvent>();
public event CustomEvent Event
{
add { lock(events) events.Add(value); }
remove { lock(events) events.Remove(value); }
}
public async Task DoneSomething()
{
List<CustomEvent> handlers;
lock(events)
handlers = this.events.ToList(); // Cache this
var tasks = handlers.Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
My application should not continue its execution before its done notifying all subscribers, where this works as long as someone do not put a async void on the callback.
I have a blog entry on designing for async event handlers. It is possible to use Task-returning delegates or to wrap an existing SynchronizationContext within your own (which would allow you to detect and wait for async void handlers).
However, I recommend you use "deferrals", which are objects designed specifically to solve this problem for Windows Store applications. A simple DeferralManager is available in my AsyncEx library.
Your event args can define a GetDeferral method as such:
public class MyEventArgs : EventArgs
{
private readonly DeferralManager deferrals = new DeferralManager();
... // Your own constructors and properties.
public IDisposable GetDeferral()
{
return deferrals.GetDeferral();
}
internal Task WaitForDeferralsAsync()
{
return deferrals.SignalAndWaitAsync();
}
}
And you can raise an event and (asynchronously) wait for all asynchronous handlers to complete like this:
private Task RaiseMyEventAsync()
{
var handler = MyEvent;
if (handler == null)
return Task.FromResult<object>(null); // or TaskConstants.Completed
var args = new MyEventArgs(...);
handler(args);
return args.WaitForDeferralsAsync();
}
The benefit of the "deferral" pattern is that it is well-established in the Windows Store APIs, so it's likely to be recognized by end users.
There's plenty of examples of people saying to use a Timer instead of Thread.Sleep(...) in an Azure Worker Role. No probs with that.
What I'm struggling to understand is how to code this.
Currently, I have the following (pseduo code)
_timer.Elapsed += (sender, args) => DoWork();
public override void Run()
{
while(true)
{
DoWork();
}
}
public void DoWork()
{
try
{
_timer.Stop();
// Now - do stuff ....
}
catch(....) { ... }
_timer.Start()
}
And what happens, is that the code enters the DoWork() method once and DoesStuff(tm).. fine .. starts the timer (say .. with a 30 second interval) and then exits that method.
Then, it returns back to the main Run() method .. which is in that loop. So it immediately comes back around and enters the DoWork() method again .. instead of waiting for the timer to fire it off.
So I'm not sure how to replace any Thread.Sleep(...) with Timers.
Any clues?
Clarification
I do not want to exit the Run() method :) I'm very happy to keep looping forever. What I'm stuck with, is replacing the standard Thread.Sleep(...) call (which blocks the thread) and replace that with a Timer, which most people suggest.
Update
Please do not link or suggest that I should use cancelSource.Token.WaitHandle.WaitOne(); as a solution. That is not what I'm trying to achieve here. Please note the post title!
I figure that if you want to solve this situation the way you outline here you will need a WaitHandle AND a Timer.
The short answer is here below. The long answer became a blog post: HowTo wait in a WorkerRole using Timer and EventWaitHandle over Thread.Sleep
I used an EventWaitHandle along with the Timer and came up with this solution:
public class WorkerRole : RoleEntryPoint
{
Waiter waiter;
public override bool OnStart()
{
waiter = new Waiter(WorkerConfiguration.WaitInterval);
return base.OnStart();
}
public override void Run()
{
while (true)
{
DoWork();
waiter.Wait();
}
}
public void DoWork()
{
// [...]
}
}
And here is the waiter class:
public class Waiter
{
private readonly Timer timer;
private readonly EventWaitHandle waitHandle;
public Waiter(TimeSpan? interval = null)
{
waitHandle = new AutoResetEvent(false);
timer = new Timer();
timer.Elapsed += (sender, args) => waitHandle.Set();
SetInterval(interval);
}
public TimeSpan Interval
{
set { timer.Interval = value.TotalMilliseconds; }
}
public void Wait(TimeSpan? newInterval = null)
{
SetInterval(newInterval);
timer.Start();
waitHandle.WaitOne();
timer.Close();
waitHandle.Reset();
}
private void SetInterval(TimeSpan? newInterval)
{
if (newInterval.HasValue)
{
Interval = newInterval.Value;
}
}
}