RazorCompilationService should throw a meaningful error when a user produces an application without `preserveCompilationContext`
Fixes #4202
This commit is contained in:
parent
bf1fc7dab3
commit
c03aabbff5
|
|
@ -85,7 +85,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
#if NETSTANDARD1_5
|
||||
_razorLoadContext = new RazorLoadContext();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -144,6 +143,18 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -462,6 +462,22 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("LayoutHasCircularReference"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Razor page '{0}' failed to compile. Ensure that your application's {1} sets the '{2}' compilation property.
|
||||
/// </summary>
|
||||
internal static string Compilation_DependencyContextIsNotSpecified
|
||||
{
|
||||
get { return GetString("Compilation_DependencyContextIsNotSpecified"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Razor page '{0}' failed to compile. Ensure that your application's {1} sets the '{2}' compilation property.
|
||||
/// </summary>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -256,6 +256,7 @@ public class MyNonCustomDefinedClass {}
|
|||
[Fact]
|
||||
public void Compile_RunsCallback()
|
||||
{
|
||||
// Arrange
|
||||
var content = "public class MyTestType {}";
|
||||
RoslynCompilationContext usedCompilation = null;
|
||||
|
||||
|
|
@ -276,6 +277,117 @@ public class MyNonCustomDefinedClass {}
|
|||
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(
|
||||
|
|
|
|||
Loading…
Reference in New Issue