Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Commit

Permalink
RazorCompilationService should throw a meaningful error when a user p…
Browse files Browse the repository at this point in the history
…roduces an application without `preserveCompilationContext`

Fixes #4202
  • Loading branch information
pranavkm committed Mar 15, 2016
1 parent bf1fc7d commit c03aabb
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ internal DefaultRoslynCompilationService(
#if NETSTANDARD1_5
_razorLoadContext = new RazorLoadContext();
#endif

}

/// <inheritdoc />
Expand Down Expand Up @@ -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,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,7 @@
<data name="LayoutHasCircularReference" xml:space="preserve">
<value>A circular layout reference was detected when rendering '{0}'. The layout page '{1}' has already been rendered.</value>
</data>
<data name="Compilation_DependencyContextIsNotSpecified" xml:space="preserve">
<value>The Razor page '{0}' failed to compile. Ensure that your application's {1} sets the '{2}' compilation property.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessa
[Fact]
public void Compile_RunsCallback()
{
// Arrange
var content = "public class MyTestType {}";
RoslynCompilationContext usedCompilation = null;

Expand All @@ -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<InvalidOperationException>(() =>
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<InvalidOperationException>(() =>
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(
Expand Down

0 comments on commit c03aabb

Please sign in to comment.