diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs index 62788e7eee..701d0204c7 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs @@ -141,11 +141,18 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation Debug.Assert(fileInfo != null && fileInfo.Exists); Debug.Assert(cacheEntryOptions != null); var relativeFileInfo = new RelativeFileInfo(fileInfo, normalizedPath); - var compilationResult = compile(relativeFileInfo); - compilationResult.EnsureSuccessful(); - compilationTaskSource.SetResult( - new CompilerCacheResult(compilationResult, cacheEntryOptions.ExpirationTokens)); + try + { + var compilationResult = compile(relativeFileInfo); + compilationResult.EnsureSuccessful(); + compilationTaskSource.SetResult( + new CompilerCacheResult(compilationResult, cacheEntryOptions.ExpirationTokens)); + } + catch (Exception ex) + { + compilationTaskSource.SetException(ex); + } } return cacheEntry; diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs index f0839969a8..292be13a3d 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Diagnostics; using Moq; using Xunit; @@ -443,6 +444,70 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation Assert.Same(result1.CompilationResult.CompiledType, result2.CompilationResult.CompiledType); } + [Fact] + public void GetOrAdd_CachesCompilationExceptions() + { + // Arrange + var fileProvider = new TestFileProvider(); + fileProvider.AddFile(ViewPath, "some content"); + var cache = new CompilerCache(fileProvider); + var exception = new InvalidTimeZoneException(); + + // Act and Assert - 1 + var actual = Assert.Throws(() => + cache.GetOrAdd(ViewPath, _ => { throw exception; })); + Assert.Same(exception, actual); + + // Act and Assert - 2 + actual = Assert.Throws(() => cache.GetOrAdd(ViewPath, ThrowsIfCalled)); + Assert.Same(exception, actual); + } + + [Fact] + public void GetOrAdd_ReturnsSuccessfulCompilationResultIfTriggerExpires() + { + // Arrange + var fileProvider = new TestFileProvider(); + fileProvider.AddFile(ViewPath, "some content"); + var cache = new CompilerCache(fileProvider); + + // Act and Assert - 1 + Assert.Throws(() => + cache.GetOrAdd(ViewPath, _ => { throw new InvalidTimeZoneException(); })); + + // Act - 2 + fileProvider.GetChangeToken(ViewPath).HasChanged = true; + var result = cache.GetOrAdd(ViewPath, _ => new CompilationResult(typeof(TestView))); + + // Assert - 2 + Assert.Same(typeof(TestView), result.CompilationResult.CompiledType); + } + + [Fact] + public void GetOrAdd_CachesExceptionsInCompilationResult() + { + // Arrange + var fileProvider = new TestFileProvider(); + fileProvider.AddFile(ViewPath, "some content"); + var cache = new CompilerCache(fileProvider); + var diagnosticMessages = new[] + { + new AspNet.Diagnostics.DiagnosticMessage("message", "message", ViewPath, 1, 1, 1, 1) + }; + var compilationResult = new CompilationResult(new[] + { + new CompilationFailure(ViewPath, "some content", "compiled content", diagnosticMessages) + }); + + // Act and Assert - 1 + var ex = Assert.Throws(() => cache.GetOrAdd(ViewPath, _ => compilationResult)); + Assert.Same(compilationResult.CompilationFailures, ex.CompilationFailures); + + // Act and Assert - 2 + ex = Assert.Throws(() => cache.GetOrAdd(ViewPath, ThrowsIfCalled)); + Assert.Same(compilationResult.CompilationFailures, ex.CompilationFailures); + } + private class TestView { }