diff --git a/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentGenerator/BackgroundDocumentGenerator.cs b/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentGenerator/BackgroundDocumentGenerator.cs index 122e577abe..2ddde78e98 100644 --- a/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentGenerator/BackgroundDocumentGenerator.cs +++ b/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentGenerator/BackgroundDocumentGenerator.cs @@ -149,12 +149,35 @@ namespace Microsoft.CodeAnalysis.Razor // Access to the timer is protected by the lock in Enqueue and in Timer_Tick if (_timer == null) { - // Timer will fire after a fixed delay, but only once. - _timer = new Timer(Timer_Tick, null, Delay, Timeout.InfiniteTimeSpan); + // Don't capture asynclocals onto Timer + bool restoreFlow = false; + try + { + if (!ExecutionContext.IsFlowSuppressed()) + { + ExecutionContext.SuppressFlow(); + restoreFlow = true; + } + + // Timer will fire after a fixed delay, but only once. + _timer = new Timer(state => ((BackgroundDocumentGenerator)state).Timer_Tick(), this, Delay, Timeout.InfiniteTimeSpan); + } + finally + { + if (restoreFlow) + { + ExecutionContext.RestoreFlow(); + } + } } } - private async void Timer_Tick(object state) // Yeah I know. + private void Timer_Tick() + { + _ = TimerTick(); + } + + private async Task TimerTick() { try { @@ -208,7 +231,8 @@ namespace Microsoft.CodeAnalysis.Razor { // This is something totally unexpected, let's just send it over to the workspace. await Task.Factory.StartNew( - () => _projectManager.ReportError(ex), + (p) => ((ProjectSnapshotManagerBase)p).ReportError(ex), + _projectManager, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); @@ -218,7 +242,8 @@ namespace Microsoft.CodeAnalysis.Razor private void ReportError(DocumentSnapshot document, Exception ex) { GC.KeepAlive(Task.Factory.StartNew( - () => _projectManager.ReportError(ex), + (p) => ((ProjectSnapshotManagerBase)p).ReportError(ex), + _projectManager, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler)); diff --git a/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs b/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs index 23ae8208c5..601dba2fc2 100644 --- a/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs +++ b/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs @@ -213,8 +213,26 @@ namespace Microsoft.VisualStudio.Editor.Razor { if (_idleTimer == null) { - // Timer will fire after a fixed delay, but only once. - _idleTimer = new Timer(Timer_Tick, null, IdleDelay, Timeout.InfiniteTimeSpan); + // Don't capture asynclocals onto Timer + bool restoreFlow = false; + try + { + if (!ExecutionContext.IsFlowSuppressed()) + { + ExecutionContext.SuppressFlow(); + restoreFlow = true; + } + + // Timer will fire after a fixed delay, but only once. + _idleTimer = new Timer(state => ((DefaultVisualStudioRazorParser)state).Timer_Tick(), this, IdleDelay, Timeout.InfiniteTimeSpan); + } + finally + { + if (restoreFlow) + { + ExecutionContext.RestoreFlow(); + } + } } } } @@ -337,7 +355,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - private void Timer_Tick(object state) + private void Timer_Tick() { try {