diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs
index 8b9a5da614..e8bed94b27 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs
@@ -85,7 +85,6 @@ internal DefaultRoslynCompilationService(
#if NETSTANDARD1_5
_razorLoadContext = new RazorLoadContext();
#endif
-
}
///
@@ -144,6 +143,18 @@ public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationCo
if (!result.Success)
{
+ if (!compilation.References.Any() && !_applicationReferences.Value.Any())
+ {
+ // DependencyModel had no references specified and the user did not use the
+ // CompilationCallback to add extra references. It is likely that the user did not specify
+ // preserveCompilationContext in the app's project.json.
+ throw new InvalidOperationException(
+ Resources.FormatCompilation_DependencyContextIsNotSpecified(
+ fileInfo.RelativePath,
+ "project.json",
+ "preserveCompilationContext"));
+ }
+
return GetCompilationFailedResult(
fileInfo.RelativePath,
compilationContent,
diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs
index 5343888a29..a89c641c01 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs
@@ -462,6 +462,22 @@ internal static string FormatLayoutHasCircularReference(object p0, object p1)
return string.Format(CultureInfo.CurrentCulture, GetString("LayoutHasCircularReference"), p0, p1);
}
+ ///
+ /// The Razor page '{0}' failed to compile. Ensure that your application's {1} sets the '{2}' compilation property.
+ ///
+ internal static string Compilation_DependencyContextIsNotSpecified
+ {
+ get { return GetString("Compilation_DependencyContextIsNotSpecified"); }
+ }
+
+ ///
+ /// The Razor page '{0}' failed to compile. Ensure that your application's {1} sets the '{2}' compilation property.
+ ///
+ internal static string FormatCompilation_DependencyContextIsNotSpecified(object p0, object p1, object p2)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("Compilation_DependencyContextIsNotSpecified"), p0, p1, p2);
+ }
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
index f94c7316aa..caac824d01 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
@@ -203,4 +203,7 @@
A circular layout reference was detected when rendering '{0}'. The layout page '{1}' has already been rendered.
+
+ The Razor page '{0}' failed to compile. Ensure that your application's {1} sets the '{2}' compilation property.
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs
index 758bb1845b..ef2a00ead3 100644
--- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs
@@ -256,6 +256,7 @@ public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessa
[Fact]
public void Compile_RunsCallback()
{
+ // Arrange
var content = "public class MyTestType {}";
RoslynCompilationContext usedCompilation = null;
@@ -276,6 +277,117 @@ public void Compile_RunsCallback()
Assert.Single(usedCompilation.Compilation.SyntaxTrees);
}
+ [Fact]
+ public void Compile_ThrowsIfDependencyContextIsNullAndTheApplicationFailsToCompileWithNoReferences()
+ {
+ // Arrange
+ var content = "public class MyTestType {}";
+ var compilationService = new DefaultRoslynCompilationService(
+ dependencyContext: null,
+ viewEngineOptions: GetOptions(),
+ fileProviderAccessor: GetFileProviderAccessor(),
+ loggerFactory: NullLoggerFactory.Instance);
+
+ var relativeFileInfo = new RelativeFileInfo(
+ new TestFileInfo { PhysicalPath = "SomePath" },
+ "some-relative-path.cshtml");
+
+ var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your "
+ + "application's project.json sets the 'preserveCompilationContext' compilation property.";
+
+ // Act and Assert
+ var ex = Assert.Throws(() =>
+ compilationService.Compile(relativeFileInfo, content));
+ Assert.Equal(expected, ex.Message);
+ }
+
+ [Fact]
+ public void Compile_ThrowsIfDependencyContextReturnsNoReferencesAndTheApplicationFailsToCompile()
+ {
+ // Arrange
+ var content = "public class MyTestType {}";
+ var dependencyContext = new DependencyContext(
+ target: null,
+ runtime: null,
+ compilationOptions: Extensions.DependencyModel.CompilationOptions.Default,
+ compileLibraries: new CompilationLibrary[0],
+ runtimeLibraries: new RuntimeLibrary[0]);
+ var compilationService = new DefaultRoslynCompilationService(
+ dependencyContext: dependencyContext,
+ viewEngineOptions: GetOptions(),
+ fileProviderAccessor: GetFileProviderAccessor(),
+ loggerFactory: NullLoggerFactory.Instance);
+
+ var relativeFileInfo = new RelativeFileInfo(
+ new TestFileInfo { PhysicalPath = "SomePath" },
+ "some-relative-path.cshtml");
+
+ var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your "
+ + "application's project.json sets the 'preserveCompilationContext' compilation property.";
+
+ // Act and Assert
+ var ex = Assert.Throws(() =>
+ compilationService.Compile(relativeFileInfo, content));
+ Assert.Equal(expected, ex.Message);
+ }
+
+ [Fact]
+ public void Compile_DoesNotThrowIfReferencesWereClearedInCallback()
+ {
+ // Arrange
+ var options = GetOptions(context =>
+ {
+ context.Compilation = context.Compilation.RemoveAllReferences();
+ });
+ var content = "public class MyTestType {}";
+ var compilationService = new DefaultRoslynCompilationService(
+ dependencyContext: GetDependencyContext(),
+ viewEngineOptions: options,
+ fileProviderAccessor: GetFileProviderAccessor(),
+ loggerFactory: NullLoggerFactory.Instance);
+
+ var relativeFileInfo = new RelativeFileInfo(
+ new TestFileInfo { PhysicalPath = "SomePath" },
+ "some-relative-path.cshtml");
+
+ // Act
+ var result = compilationService.Compile(relativeFileInfo, content);
+
+ // Assert
+ Assert.Single(result.CompilationFailures);
+ }
+
+ [Fact]
+ public void Compile_SucceedsIfReferencesAreAddedInCallback()
+ {
+ // Arrange
+ var options = GetOptions(context =>
+ {
+ var assemblyLocation = typeof(object).GetTypeInfo().Assembly.Location;
+
+ context.Compilation = context
+ .Compilation
+ .AddReferences(MetadataReference.CreateFromFile(assemblyLocation));
+ });
+ var content = "public class MyTestType {}";
+ var compilationService = new DefaultRoslynCompilationService(
+ dependencyContext: null,
+ viewEngineOptions: options,
+ fileProviderAccessor: GetFileProviderAccessor(),
+ loggerFactory: NullLoggerFactory.Instance);
+
+ var relativeFileInfo = new RelativeFileInfo(
+ new TestFileInfo { PhysicalPath = "SomePath" },
+ "some-relative-path.cshtml");
+
+ // Act
+ var result = compilationService.Compile(relativeFileInfo, content);
+
+ // Assert
+ Assert.Null(result.CompilationFailures);
+ Assert.NotNull(result.CompiledType);
+ }
+
private static DiagnosticDescriptor GetDiagnosticDescriptor(string messageFormat)
{
return new DiagnosticDescriptor(