I am writing a WPF project, using C# 5 and async/await.
I'd like to, during development, add some code that will alert the developer any task takes longer than a certain period of time. This will ensure that the developer never accidentally does file/network IO on the UI thread, as well as any other long running computations that should be moved to another thread.
Is there somewhere to override the TaskScheduler, to wrap each Task with the following?
private Task WrapTask(Task task)
{
    return Task.Run(async () =>
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        await task;
        stopwatch.Stop();
        if (stopwatch.Elapsed > TimeSpan.FromMilliseconds(5))
        {
            // TODO: Log
            Debug.WriteLine("A task took longer than expected.");
        }
    });
}
This should be transparent to the user, and also should be used when in the context of an async/await method.
THIS DOESN'T WORK AT ALL, JUST TO ILLUSTRATE: Maybe wrapping a TaskScheduler like this, and then someone replacing the current one?
public class TaskSchedulerTimer : TaskScheduler
{
    private readonly TaskScheduler _taskScheduler;
    private readonly MethodInfo _queueTaskMethod;
    private readonly MethodInfo _tryExecuteTaskInlineMethod;
    private readonly MethodInfo _getScheduledTasksMethod;
    public TaskSchedulerTimer(TaskScheduler taskScheduler)
    {
        _taskScheduler = taskScheduler;
        _queueTaskMethod = typeof(TaskScheduler).GetMethod("QueueTask");
        _tryExecuteTaskInlineMethod = typeof(TaskScheduler).GetMethod("TryExecuteTaskInline");
        _getScheduledTasksMethod = typeof(TaskScheduler).GetMethod("GetScheduledTasks");
    }
    protected override void QueueTask(Task task)
    {
        _queueTaskMethod.Invoke(_taskScheduler, new object[] { WrapTask(task) });
    }
    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        return (bool)_tryExecuteTaskInlineMethod.Invoke(_taskScheduler, new object[] { WrapTask(task), taskWasPreviouslyQueued });
    }
    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return (IEnumerable<Task>)_getScheduledTasksMethod.Invoke(_taskScheduler, new object[] { });
    }
    private Task WrapTask(Task task)
    {
        return Task.Run(async () =>
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            await task;
            stopwatch.Stop();
            if (stopwatch.Elapsed > TimeSpan.FromMilliseconds(5))
            {
                // TODO: Log
                Debug.WriteLine("A task took longer than expected.");
            }
        });
    }
}
Maybe I need to go lower, to the SynchronizationContext, and do something similar there?
UPDATE: It seems that the current TaskScheduler used in WPF wraps around the Dispatcher. There appears to be some hooks on there, so I am covered for my purposes. However, I'd still like to know if my original question has a good answer.
FYI, here is my code for the timing stuff, in WPF.
private readonly Stopwatch _currentOperation = new Stopwatch();
Dispatcher.Hooks.OperationStarted += HooksOnOperationStarted;
Dispatcher.Hooks.OperationCompleted += HooksOnOperationCompleted;
Dispatcher.Hooks.OperationAborted += HooksOnOperationAborted;
private void HooksOnOperationStarted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs)
{
    Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId);
    _currentOperation.Start();
}
private void HooksOnOperationCompleted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs)
{
    Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId);
    _currentOperation.Stop();
    if (_currentOperation.Elapsed > TimeSpan.FromMilliseconds(5))
    {
        // TODO: Log
        Debug.WriteLine("A task took longer than expected.");
    }
    _currentOperation.Reset();
}
private void HooksOnOperationAborted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs)
{
    Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId);
    _currentOperation.Stop();
    if (_currentOperation.Elapsed > TimeSpan.FromMilliseconds(5))
    {
        // TODO: Log
        Debug.WriteLine("A task took longer than expected.");
    }
    _currentOperation.Reset();
}
