I have a method using
HostingEnvironment.QueueBackgroundWorkItem
which I wish to unit test some behaviour before this call, however, the test is failing with System.InvalidOperationException : Operation is not valid due to the current state of the object.
I suspect this I need to mock the HostingEnvironment but unaware of how to.
To resolve this issue I defined an interface
public interface ITaskScheduler
{
void QueueBackgroundWorkItem(Action<CancellationToken> workItem);
}
In production code I inject implementation
public class AspNetTaskScheduler : ITaskScheduler
{
public void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
{
HostingEnvironment.QueueBackgroundWorkItem(workItem);
}
}
In test code I inject implementation
public class TaskScheduler : ITaskScheduler
{
public void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
{
workItem.Invoke(new CancellationToken());
}
}
I think this is an OK solution since unit tests work and my classes that queue background tasks are decoupled from HostingEnvironment
.
I ended up doing this to keep things simple:
/// <summary>
/// add some jobs to the background queue
/// </summary>
public static class BackgroundTaskScheduler
{
/// <summary>
/// send the work item to the background queue
/// </summary>
/// <param name="workItem">work item to enqueue</param>
public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
{
try
{
HostingEnvironment.QueueBackgroundWorkItem(workItem);
}
catch (InvalidOperationException)
{
workItem.Invoke(new CancellationToken());
}
}
}
Then to fire a job simply:
BackgroundTaskScheduler.QueueBackgroundWorkItem(ct =>
{
// bla
});
A little bit neater than calling HostingEnvironment.QueueBackgroundWorkItem
regardless of whether there's an ASP.NET AppDomain then catching the InvalidOperationException
is:
public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
{
if (HostingEnvironment.IsHosted)
{
HostingEnvironment.QueueBackgroundWorkItem(workItem);
}
else
{
workItem.Invoke(new CancellationToken());
}
}