I have implemented an http module which will be fired on application start of my ASP.NET application
using System.Web;
using System.Threading.Tasks;
using System;
using System.Net.Http;
namespace BL.HttpModules
{
public class MyCustomAsyncModule : IHttpModule
{
#region Static Privates
private static bool applicationStarted = false;
private readonly static object applicationStartLock = new object();
#endregion
public void Dispose()
{
}
/// <summary>
/// Initializes the specified module.
/// </summary>
/// <param name="httpApplication">The application context that instantiated and will be running this module.</param>
public void Init(HttpApplication httpApplication)
{
if (!applicationStarted)
{
lock (applicationStartLock)
{
if (!applicationStarted)
{
// this will run only once per application start
this.OnStart(httpApplication);
}
}
}
// this will run on every HttpApplication initialization in the application pool
this.OnInit(httpApplication);
}
public virtual void OnStart(HttpApplication httpApplication)
{
httpApplication.AddOnBeginRequestAsync(OnBegin, OnEnd);
}
private IAsyncResult OnBegin(object sender, EventArgs e, AsyncCallback cb, object extraData)
{
applicationStarted = true;
var tcs = new TaskCompletionSource<object>(extraData);
DoAsyncWork(HttpContext.Current).ContinueWith(t =>
{
if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerExceptions);
}
else
{
tcs.SetResult(null);
}
if (cb != null) cb(tcs.Task);
});
return tcs.Task;
}
async Task DoAsyncWork(HttpContext ctx)
{
var client = new HttpClient();
var result = await client.GetStringAsync("http://google.com");
// USE RESULT
}
private void OnEnd(IAsyncResult ar)
{
Task t = (Task)ar;
t.Wait();
}
/// <summary>Initializes any data/resources on HTTP module start.</summary>
/// <param name="httpApplication">The application context that instantiated and will be running this module.</param>
public virtual void OnInit(HttpApplication httpApplication)
{
// put your module initialization code here
}
}// end class
}// end namespace
I want to fire DoAsyncWork after each 5 minutes. Can you help me achieving that goal in that module?
There is no built in way in IIS to reliably do this, you need to use a external process or a 3rd party library to scheduled the work to be done. Hangfire is a very popular library that lets you do both in process and out of process scheduled tasks.
Related
I need a custom SynchronizationContext that:
Owns a single thread that runs "Posts" and "Sends" delegates
Does the send in the order they are send in
No other methods are needed
I need this so I can unit test some threading code that will talk to WinForm in the real application.
Before I write my own, I was hoping that someone could point me to a simple (and small) implementations.
This one was written by me some time ago, no issues with copyright, no guarantees either(the system didn't go into production):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Threading;
namespace ManagedHelpers.Threads
{
public class STASynchronizationContext : SynchronizationContext, IDisposable
{
private readonly Dispatcher dispatcher;
private object dispObj;
private readonly Thread mainThread;
public STASynchronizationContext()
{
mainThread = new Thread(MainThread) { Name = "STASynchronizationContextMainThread", IsBackground = false };
mainThread.SetApartmentState(ApartmentState.STA);
mainThread.Start();
//wait to get the main thread's dispatcher
while (Thread.VolatileRead(ref dispObj) == null)
Thread.Yield();
dispatcher = dispObj as Dispatcher;
}
public override void Post(SendOrPostCallback d, object state)
{
dispatcher.BeginInvoke(d, new object[] { state });
}
public override void Send(SendOrPostCallback d, object state)
{
dispatcher.Invoke(d, new object[] { state });
}
private void MainThread(object param)
{
Thread.VolatileWrite(ref dispObj, Dispatcher.CurrentDispatcher);
Console.WriteLine("Main Thread is setup ! Id = {0}", Thread.CurrentThread.ManagedThreadId);
Dispatcher.Run();
}
public void Dispose()
{
if (!dispatcher.HasShutdownStarted && !dispatcher.HasShutdownFinished)
dispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
GC.SuppressFinalize(this);
}
~STASynchronizationContext()
{
Dispose();
}
}
}
idesign.net (search for Custom Synchronization Context on the page) has a SynchronizationContext that will do the job, however it is more complex them I need.
Had a similar requirement - unit testing a server component to confirm that it's callback delegate invocations were marshalled onto an appropriate SynchronizationContext and came up with the following code (based on Stephen Toub's blog post http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx) which I recon is simpler and more general as it uses it's own internal thread to service the Post()/Send() requests, rather than relying on WPF/Winforms/.. to perform dispatching.
// A simple SynchronizationContext that encapsulates it's own dedicated task queue and processing
// thread for servicing Send() & Post() calls.
// Based upon http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx but uses it's own thread
// rather than running on the thread that it's instanciated on
public sealed class DedicatedThreadSynchronisationContext : SynchronizationContext, IDisposable
{
public DedicatedThreadSynchronisationContext()
{
m_thread = new Thread(ThreadWorkerDelegate);
m_thread.Start(this);
}
public void Dispose()
{
m_queue.CompleteAdding();
}
/// <summary>Dispatches an asynchronous message to the synchronization context.</summary>
/// <param name="d">The System.Threading.SendOrPostCallback delegate to call.</param>
/// <param name="state">The object passed to the delegate.</param>
public override void Post(SendOrPostCallback d, object state)
{
if (d == null) throw new ArgumentNullException("d");
m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
}
/// <summary> As
public override void Send(SendOrPostCallback d, object state)
{
using (var handledEvent = new ManualResetEvent(false))
{
Post(SendOrPostCallback_BlockingWrapper, Tuple.Create(d, state, handledEvent));
handledEvent.WaitOne();
}
}
public int WorkerThreadId { get { return m_thread.ManagedThreadId; } }
//=========================================================================================
private static void SendOrPostCallback_BlockingWrapper(object state)
{
var innerCallback = (state as Tuple<SendOrPostCallback, object, ManualResetEvent>);
try
{
innerCallback.Item1(innerCallback.Item2);
}
finally
{
innerCallback.Item3.Set();
}
}
/// <summary>The queue of work items.</summary>
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue =
new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
private readonly Thread m_thread = null;
/// <summary>Runs an loop to process all queued work items.</summary>
private void ThreadWorkerDelegate(object obj)
{
SynchronizationContext.SetSynchronizationContext(obj as SynchronizationContext);
try
{
foreach (var workItem in m_queue.GetConsumingEnumerable())
workItem.Key(workItem.Value);
}
catch (ObjectDisposedException) { }
}
}
Some modern unit testing libraries (e.g., xUnit) already include single-threaded SynchronizationContext instances by default. Others do not (e.g., MSTest).
My AsyncEx library has an AsyncContext that installs a single-threaded SynchronizationContext and just processes the queue of messages on that single thread. Usage is quite simple:
public Task MyTestMethod() => AsyncContext.Run(async () =>
{
// asynchronous code here.
});
AsyncContext was designed for unit tests and Console applications, and has proper handling of some more exotic scenarios, e.g.:
async void methods are detected and the Run method will not return until they are complete.
AsyncContext.Run allows returning a result value, useful if you want to do your assertions outside of the asynchronous code.
If the delegate passed to Run propagates an exception or if any exception is propagated out of an async void method, then that exception propagates out of AsyncContext.Run (without exception wrappers and preserving the exception call stack).
However, AsyncContext is just a SynchronizationContext (with a "runner"), and has no notion of UI-specific thread synchronization mechanisms (e.g., Dispatcher, Control.Invoke). If you need to test code that uses a dispatcher or control, then you'll need to use WpfContext or WindowsFormsContext, which were helper types from the original Async CTP.
I have adapted the answer by Bond to remove the dependency on WPF (Dispatcher), and depend on WinForms instead:
namespace ManagedHelpers.Threads
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using NUnit.Framework;
public class STASynchronizationContext : SynchronizationContext, IDisposable
{
private readonly Control control;
private readonly int mainThreadId;
public STASynchronizationContext()
{
this.control = new Control();
this.control.CreateControl();
this.mainThreadId = Thread.CurrentThread.ManagedThreadId;
if (Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "AsynchronousTestRunner Main Thread";
}
}
public override void Post(SendOrPostCallback d, object state)
{
control.BeginInvoke(d, new object[] { state });
}
public override void Send(SendOrPostCallback d, object state)
{
control.Invoke(d, new object[] { state });
}
public void Dispose()
{
Assert.AreEqual(this.mainThreadId, Thread.CurrentThread.ManagedThreadId);
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
Assert.AreEqual(this.mainThreadId, Thread.CurrentThread.ManagedThreadId);
if (disposing)
{
if (control != null)
{
control.Dispose();
}
}
}
~STASynchronizationContext()
{
this.Dispose(false);
}
}
}
Using the following Microsoft web page as a reference..
https://learn.microsoft.com/en-us/windows/msix/store-developer-package-update
I am trying to write code to update a test application I have uploaded to the Microsoft Store. Uploaded to the store is a simple dialog and a few updates (changed background color) written in C# Windows Forms using a UWP wrapper in the form of a Windows Application Packaging Project.
The dialog has a couple of buttons, one of which calls the following cut/paste methods from the above webpage..
private async void InstallUpdatesAsync()
{
StoreContext updateManager = StoreContext.GetDefault();
IReadOnlyList<StorePackageUpdate> updates = await updateManager.GetAppAndOptionalStorePackageUpdatesAsync();
// Save app state here
IAsyncOperationWithProgress<StorePackageUpdateResult, StorePackageUpdateStatus> installOperation =
updateManager.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);
StorePackageUpdateResult result = await installOperation.AsTask();
// Under normal circumstances, app will terminate here
// Handle error cases here using StorePackageUpdateResult from above
}
I am getting the error..
System.Reflection.TargetInvocationException: 'Exception has been
thrown by the target of an invocation.'
Inner Exception Exception: Invalid window handle.
This function must be called from a UI thread
I don't understand this as I am calling it from a button from a dialog box. I have seen various comments elsewhere that the commands have to be called from a UI thread, but I cannot find out how.
Any help much appreciated.
EDIT:
private void installButton_Click(object sender, EventArgs e)
{
rtb.SelectionColor = CommandColor;
rtb.AppendText("Installing updates\n\n");
InstallUpdatesAsync();
}
Try creating your own helper class and use it's RunSync extension method, it will be your universal solution, eliminating requirement to adapt different Dispatcher implementations from different platforms.
public static class AsyncHelpers
{
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default;
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private readonly Queue<Tuple<SendOrPostCallback, object>> _Items =
new Queue<Tuple<SendOrPostCallback, object>>();
private readonly AutoResetEvent _WorkItemsWaiting = new AutoResetEvent(false);
private bool _Done;
public Exception InnerException { get; set; }
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
public override void Post(SendOrPostCallback d, object state)
{
lock (_Items)
{
_Items.Enqueue(Tuple.Create(d, state));
}
_WorkItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => _Done = true, null);
}
public void BeginMessageLoop()
{
while (!_Done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (_Items)
{
if (_Items.Count > 0) task = _Items.Dequeue();
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
}
else
{
_WorkItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
}
I did not work in UWP, but some controls are inside the UI thread and because the function that is running is multiple threads, it is not allowed to run. I put a code below but I do not know if it works or not.
private async void installButton_Click(object sender, EventArgs e)
{
rtb.SelectionColor = CommandColor;
rtb.AppendText("Installing updates\n\n");
await this.Dispatcher.RunAsync(CoreDispatcherPriority.High, () => {
InstallUpdatesAsync()
});
}
I would like to use Condition Variable in order to know when Messages Queue is not empty, i would like to use it in "HandleMessageQueue" as a thread
private static Queue<Message> messages = new Queue<Message>();
/// <summary>
/// function return the first message
/// </summary>
/// <returns>first message element</returns>
public static Message GetFirst()
{
return messages.Dequeue();
}
in another class:
/// <summary>
/// Function run while the clients connected and handle the queue message
/// </summary>
public static void HandleMessageQueue()
{
// ...
}
What you're probably looking for is a simple producer-consumer pattern. In this case I'd recommend using .NET's BlockingCollection, which allows you to easily handle the following cases:
have one thread push stuff in a queue
have another thread block until stuff is available
make the whole thing easy to shutdown without having to forcibly terminate the thread
Here's a short code sample, read the comments for more information about what every bit does:
public class Queue : IDisposable
{
private readonly Thread _messageThread; // thread for processing messages
private readonly BlockingCollection<Message> _messages; // queue for messages
private readonly CancellationTokenSource _cancellation; // used to abort the processing when we're done
// initializes everything and starts a processing thread
public Queue()
{
_messages = new BlockingCollection<Message>();
_cancellation = new CancellationTokenSource();
_messageThread = new Thread(ProcessMessages);
_messageThread.Start();
}
// processing thread function
private void ProcessMessages()
{
try
{
while (!_cancellation.IsCancellationRequested)
{
// Take() blocks until either:
// 1) a message is available, in which case it returns it, or
// 2) the cancellation token is cancelled, in which case it throws an OperationCanceledException
var message = _messages.Take(_cancellation.Token);
// process the message here
}
}
catch (OperationCanceledException)
{
// Take() was cancelled, let the thread exit
}
}
// pushes a message
public void QueueMessage(Message message)
{
_messages.Add(message);
}
// stops processing and clean up resources
public void Dispose()
{
_cancellation.Cancel(); // let Take() abort by throwing
_messageThread.Join(); // wait for thread to exit
_cancellation.Dispose(); // release the cancellation source
_messages.Dispose(); // release the queue
}
}
Another option would be to combine a ConcurrentQueue<T> with a ManualResetEvent (events are roughly the .NET equivalent to condition variables), but that would be doing by hand what BlockingCollection<T> does).
something like this?
public class EventArgs<T> : EventArgs
{
private T eventData;
public EventArgs(T eventData)
{
this.eventData = eventData;
}
public T EventData
{
get { return eventData; }
}
}
public class ObservableQueue<T>
{
public event EventHandler<EventArgs<T>> EnQueued;
public event EventHandler<EventArgs<T>> DeQueued;
public int Count { get { return queue.Count; } }
private readonly Queue<T> queue = new Queue<T>();
protected virtual void OnEnqueued(T item)
{
if (EnQueued != null)
EnQueued(this, new EventArgs<T>(item));
}
protected virtual void OnDequeued(T item)
{
if (DeQueued != null)
DeQueued(this, new EventArgs<T>(item));
}
public virtual void Enqueue(T item)
{
queue.Enqueue(item);
OnEnqueued(item);
}
public virtual T Dequeue()
{
var item = queue.Dequeue();
OnDequeued(item);
return item;
}
}
and use it
static void Main(string[] args)
{
ObservableQueue<string> observableQueue = new ObservableQueue<string>();
observableQueue.EnQueued += ObservableQueue_EnQueued;
observableQueue.DeQueued += ObservableQueue_DeQueued;
observableQueue.Enqueue("abc");
observableQueue.Dequeue();
Console.Read();
}
I have written a Windows Service which triggers email ONCE in a WEEK at specific time. The service runs perfectly fine. Code is shown below:
protected override void OnStart(string[] args)
{
this.Log("Simple Service Started");
this.ScheduleService();
}
protected override void OnStop()
{
this.Log("Simple Service Stopped");
this.Schedular.Dispose();
}
private Timer Schedular;
public void ScheduleService()
{
try
{
Schedular = new Timer(new TimerCallback(SchedularCallback));
// Code that schedules the Callback
}
}
private void SchedularCallback(object e)
{
try
{
// Scheduled Job code
}
}
Now I have another similar requirement where I have to trigger another email, but its schedule has to be ONCE in 2 WEEKS. Is there a way this job can be accommodated in the same service, or I have to write another service?
I once did a similar design in one of my projects.
Try having a base abstract "ScheduledTask" class that defines your timing behavior, and have it used by inherited tasks classes.
Here is what I did for timers, I think there's only little work to change it to a Scheduler.
internal abstract class TaskBase
{
/// <summary>
/// Task timer
/// </summary>
private readonly Timer _timer;
/// <summary>
/// Set refresh time
/// </summary>
protected int TimeRefreshSec { get; private set; }
/// <summary>
/// Loop of timePassed
/// </summary>
protected int TimePassed { get; private set; }
protected TaskBase(double refreshInterval)
{
TimeRefreshSec = (int) refreshInterval / 1000;
TimePassed = 0;
_timer = new Timer(refreshInterval) { AutoReset = true };
_timer.Elapsed += Tick;
}
private void Tick(object sender, ElapsedEventArgs e)
{
TimePassed += TimeRefreshSec;
Tick();
}
public void Start()
{
ResetTimer();
// Run the task once when starting instead of waiting for a full interval.
Tick();
OnStart();
}
public void Stop()
{
if (_timer.Enabled)
{
_timer.Stop();
OnStop();
}
}
protected virtual void ResetTimer()
{
TimePassed = 0;
if (_timer.Enabled) _timer.Stop();
_timer.Start();
}
/// <summary>
/// Implement here a specific behavior when task is stopped.
/// </summary>
protected abstract void OnStop();
/// <summary>
/// Implement here a specific behavior when task is started.
/// </summary>
protected abstract void OnStart();
/// <summary>
/// This method is executed each time the task's timer has reached the interval specified in the constructor.
/// Time counters are automatically updated.
/// </summary>
protected abstract void Tick();
}
and for the service :
public partial class MyService : ServiceBase
{
private readonly List<TaskBase> _tasks;
public MyService()
{
InitializeComponent();
// Add in this list the tasks to run periodically.
// Tasks frequencies are set in the corresponding classes.
_tasks = new List<TaskBase>
{
new InheritingTask(),
new OherInheritingTask()
};
}
protected override void OnStart(string[] args)
{
try
{
_tasks.ForEach(t => t.Start());
}
catch (Exception ex)
{
Stop();
}
}
protected override void OnStop()
{
_tasks.ForEach(t => t.Stop());
}
}
EDIT:
The code for a class inheriting TaskBase:
class InheritingTask: TaskBase
{
public InheritingTask()
: base(Settings.Default.InheritingTaskInterval) // In milliseconds
{
//TODO: Custom initialization here
}
protected override void Tick()
{
//TODO: Task logic here
}
protected override void OnStart()
{ }
protected override void OnStop()
{ }
protected override void ResetTimer()
{
//TODO: Custom reset logic here
base.ResetTimer();
}
}
You could easily make a 2nd Schedular that is started in ScheduleService that is set to go off in two weeks however a Timer that fires once a week or two is a horrible way to do this, if the computer reboots you loose your timer and the email you where waiting on will not get sent.
You need a database of some kind to store when the next event should fire to survive restarts of your program, use a library that stores and does the scheduling for you like Hangfire.
Yes, you can achieve this using multithreading, for example via Tasks or Backgroundworkers. With this you can start each timer on a different thread which executes your operation when the timer ticks. It would also be advisable to separate timer and execution on different threads - for example Backgroundworkers for Timer 1 and 2 and Backgroundworkers for Execution 1 and 2.
I need a custom SynchronizationContext that:
Owns a single thread that runs "Posts" and "Sends" delegates
Does the send in the order they are send in
No other methods are needed
I need this so I can unit test some threading code that will talk to WinForm in the real application.
Before I write my own, I was hoping that someone could point me to a simple (and small) implementations.
This one was written by me some time ago, no issues with copyright, no guarantees either(the system didn't go into production):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Threading;
namespace ManagedHelpers.Threads
{
public class STASynchronizationContext : SynchronizationContext, IDisposable
{
private readonly Dispatcher dispatcher;
private object dispObj;
private readonly Thread mainThread;
public STASynchronizationContext()
{
mainThread = new Thread(MainThread) { Name = "STASynchronizationContextMainThread", IsBackground = false };
mainThread.SetApartmentState(ApartmentState.STA);
mainThread.Start();
//wait to get the main thread's dispatcher
while (Thread.VolatileRead(ref dispObj) == null)
Thread.Yield();
dispatcher = dispObj as Dispatcher;
}
public override void Post(SendOrPostCallback d, object state)
{
dispatcher.BeginInvoke(d, new object[] { state });
}
public override void Send(SendOrPostCallback d, object state)
{
dispatcher.Invoke(d, new object[] { state });
}
private void MainThread(object param)
{
Thread.VolatileWrite(ref dispObj, Dispatcher.CurrentDispatcher);
Console.WriteLine("Main Thread is setup ! Id = {0}", Thread.CurrentThread.ManagedThreadId);
Dispatcher.Run();
}
public void Dispose()
{
if (!dispatcher.HasShutdownStarted && !dispatcher.HasShutdownFinished)
dispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
GC.SuppressFinalize(this);
}
~STASynchronizationContext()
{
Dispose();
}
}
}
idesign.net (search for Custom Synchronization Context on the page) has a SynchronizationContext that will do the job, however it is more complex them I need.
Had a similar requirement - unit testing a server component to confirm that it's callback delegate invocations were marshalled onto an appropriate SynchronizationContext and came up with the following code (based on Stephen Toub's blog post http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx) which I recon is simpler and more general as it uses it's own internal thread to service the Post()/Send() requests, rather than relying on WPF/Winforms/.. to perform dispatching.
// A simple SynchronizationContext that encapsulates it's own dedicated task queue and processing
// thread for servicing Send() & Post() calls.
// Based upon http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx but uses it's own thread
// rather than running on the thread that it's instanciated on
public sealed class DedicatedThreadSynchronisationContext : SynchronizationContext, IDisposable
{
public DedicatedThreadSynchronisationContext()
{
m_thread = new Thread(ThreadWorkerDelegate);
m_thread.Start(this);
}
public void Dispose()
{
m_queue.CompleteAdding();
}
/// <summary>Dispatches an asynchronous message to the synchronization context.</summary>
/// <param name="d">The System.Threading.SendOrPostCallback delegate to call.</param>
/// <param name="state">The object passed to the delegate.</param>
public override void Post(SendOrPostCallback d, object state)
{
if (d == null) throw new ArgumentNullException("d");
m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
}
/// <summary> As
public override void Send(SendOrPostCallback d, object state)
{
using (var handledEvent = new ManualResetEvent(false))
{
Post(SendOrPostCallback_BlockingWrapper, Tuple.Create(d, state, handledEvent));
handledEvent.WaitOne();
}
}
public int WorkerThreadId { get { return m_thread.ManagedThreadId; } }
//=========================================================================================
private static void SendOrPostCallback_BlockingWrapper(object state)
{
var innerCallback = (state as Tuple<SendOrPostCallback, object, ManualResetEvent>);
try
{
innerCallback.Item1(innerCallback.Item2);
}
finally
{
innerCallback.Item3.Set();
}
}
/// <summary>The queue of work items.</summary>
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue =
new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
private readonly Thread m_thread = null;
/// <summary>Runs an loop to process all queued work items.</summary>
private void ThreadWorkerDelegate(object obj)
{
SynchronizationContext.SetSynchronizationContext(obj as SynchronizationContext);
try
{
foreach (var workItem in m_queue.GetConsumingEnumerable())
workItem.Key(workItem.Value);
}
catch (ObjectDisposedException) { }
}
}
Some modern unit testing libraries (e.g., xUnit) already include single-threaded SynchronizationContext instances by default. Others do not (e.g., MSTest).
My AsyncEx library has an AsyncContext that installs a single-threaded SynchronizationContext and just processes the queue of messages on that single thread. Usage is quite simple:
public Task MyTestMethod() => AsyncContext.Run(async () =>
{
// asynchronous code here.
});
AsyncContext was designed for unit tests and Console applications, and has proper handling of some more exotic scenarios, e.g.:
async void methods are detected and the Run method will not return until they are complete.
AsyncContext.Run allows returning a result value, useful if you want to do your assertions outside of the asynchronous code.
If the delegate passed to Run propagates an exception or if any exception is propagated out of an async void method, then that exception propagates out of AsyncContext.Run (without exception wrappers and preserving the exception call stack).
However, AsyncContext is just a SynchronizationContext (with a "runner"), and has no notion of UI-specific thread synchronization mechanisms (e.g., Dispatcher, Control.Invoke). If you need to test code that uses a dispatcher or control, then you'll need to use WpfContext or WindowsFormsContext, which were helper types from the original Async CTP.
I have adapted the answer by Bond to remove the dependency on WPF (Dispatcher), and depend on WinForms instead:
namespace ManagedHelpers.Threads
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using NUnit.Framework;
public class STASynchronizationContext : SynchronizationContext, IDisposable
{
private readonly Control control;
private readonly int mainThreadId;
public STASynchronizationContext()
{
this.control = new Control();
this.control.CreateControl();
this.mainThreadId = Thread.CurrentThread.ManagedThreadId;
if (Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "AsynchronousTestRunner Main Thread";
}
}
public override void Post(SendOrPostCallback d, object state)
{
control.BeginInvoke(d, new object[] { state });
}
public override void Send(SendOrPostCallback d, object state)
{
control.Invoke(d, new object[] { state });
}
public void Dispose()
{
Assert.AreEqual(this.mainThreadId, Thread.CurrentThread.ManagedThreadId);
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
Assert.AreEqual(this.mainThreadId, Thread.CurrentThread.ManagedThreadId);
if (disposing)
{
if (control != null)
{
control.Dispose();
}
}
}
~STASynchronizationContext()
{
this.Dispose(false);
}
}
}