* Redesign CompilationResult so that it does not throw when CompiledType is
accessed. * Update to use ICompilationException interface from Microsoft.Framework.Runtime * Update to use RoslynCompilationException Fixes #955
This commit is contained in:
parent
1d578ca2fd
commit
717c2bfd39
|
|
@ -3,13 +3,14 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Diagnostics;
|
||||
using System.Linq;
|
||||
using Microsoft.Framework.Runtime;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception thrown when accessing the result of a failed compilation.
|
||||
/// An <see cref="Exception"/> thrown when accessing the result of a failed compilation.
|
||||
/// </summary>
|
||||
public class CompilationFailedException : Exception, ICompilationException
|
||||
{
|
||||
|
|
@ -20,12 +21,19 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// details of the compilation failure.</param>
|
||||
public CompilationFailedException(
|
||||
[NotNull] ICompilationFailure compilationFailure)
|
||||
: base(Resources.FormatCompilationFailed(compilationFailure.SourceFilePath))
|
||||
: base(FormatMessage(compilationFailure))
|
||||
{
|
||||
CompilationFailures = new[] { compilationFailure };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ICompilationFailure> CompilationFailures { get; }
|
||||
|
||||
private static string FormatMessage(ICompilationFailure compilationFailure)
|
||||
{
|
||||
return Resources.CompilationFailed +
|
||||
Environment.NewLine +
|
||||
string.Join(Environment.NewLine, compilationFailure.Messages.Select(message => message.FormattedMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Diagnostics;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="ICompilationFailure"/>.
|
||||
/// </summary>
|
||||
public class CompilationFailure : ICompilationFailure
|
||||
{
|
||||
/// <summary>Initializes a new instance of <see cref="CompilationFailure"/>.</summary>
|
||||
/// <param name="filePath">The path of the Razor source file that was compiled.</param>
|
||||
/// <param name="fileContent">The contents of the Razor source file.</param>
|
||||
/// <param name="compiledContent">The generated C# content that was compiled.</param>
|
||||
/// <param name="messages">A sequence of <see cref="ICompilationMessage"/> encountered
|
||||
/// during compilation.</param>
|
||||
public CompilationFailure(
|
||||
[NotNull] string filePath,
|
||||
[NotNull] string fileContent,
|
||||
[NotNull] string compiledContent,
|
||||
[NotNull] IEnumerable<ICompilationMessage> messages)
|
||||
{
|
||||
SourceFilePath = filePath;
|
||||
SourceFileContent = fileContent;
|
||||
Messages = messages;
|
||||
CompiledContent = compiledContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the Razor source file that produced the compilation failure.
|
||||
/// </summary>
|
||||
public string SourceFilePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of the Razor source file.
|
||||
/// </summary>
|
||||
public string SourceFileContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the generated C# content that was compiled.
|
||||
/// </summary>
|
||||
public string CompiledContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a sequence of <see cref="ICompilationMessage"/> instances encountered during compilation.
|
||||
/// </summary>
|
||||
public IEnumerable<ICompilationMessage> Messages { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a message encountered during compilation.
|
||||
/// </summary>
|
||||
public class CompilationMessage : ICompilationMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="CompilationMessage"/> with the specified message.
|
||||
/// </summary>
|
||||
/// <param name="message">A message <see cref="string"/> produced from compilation.</param>
|
||||
public CompilationMessage(string message,
|
||||
int startColumn,
|
||||
int startLine,
|
||||
int endColumn,
|
||||
int endLine)
|
||||
{
|
||||
Message = message;
|
||||
StartColumn = startColumn;
|
||||
StartLine = startLine;
|
||||
EndColumn = endColumn;
|
||||
EndLine = endLine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a message produced from compilation.
|
||||
/// </summary>
|
||||
public string Message { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int StartColumn { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int StartLine { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int EndColumn { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int EndLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> representation of this instance of <see cref="CompilationMessage"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="string"/> representing this <see cref="CompilationMessage"/> instance.</returns>
|
||||
/// <remarks>Returns same value as <see cref="Message"/>.</remarks>
|
||||
public override string ToString()
|
||||
{
|
||||
return Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.Framework.Runtime;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
|
|
@ -14,8 +12,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// </summary>
|
||||
public class CompilationResult
|
||||
{
|
||||
private Type _type;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="CompilationResult"/>.
|
||||
/// </summary>
|
||||
|
|
@ -24,24 +20,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the Razor file that was compiled.
|
||||
/// Gets (or sets in derived types) the type produced as a result of compilation.
|
||||
/// </summary>
|
||||
public string FilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (File != null)
|
||||
{
|
||||
return File.PhysicalPath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a sequence of <see cref="CompilationMessage"/> instances encountered during compilation.
|
||||
/// </summary>
|
||||
public IEnumerable<CompilationMessage> Messages { get; private set; }
|
||||
/// <remarks>This property is <c>null</c> when compilation failed.</remarks>
|
||||
public Type CompiledType { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets (or sets in derived types) the generated C# content that was compiled.
|
||||
|
|
@ -49,52 +31,45 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public string CompiledContent { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets (or sets in derived types) the type produced as a result of compilation.
|
||||
/// Gets the <see cref="ICompilationFailure"/> produced from parsing or compiling the Razor file.
|
||||
/// </summary>
|
||||
/// <exception cref="CompilationFailedException">An error occured during compilation.</exception>
|
||||
public Type CompiledType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_type == null)
|
||||
{
|
||||
throw CreateCompilationFailedException();
|
||||
}
|
||||
|
||||
return _type;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_type = value;
|
||||
}
|
||||
}
|
||||
|
||||
private IFileInfo File { get; set; }
|
||||
/// <remarks>This property is <c>null</c> when compilation succeeded.</remarks>
|
||||
public ICompilationFailure CompilationFailure { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CompilationResult"/> that represents a failure in compilation.
|
||||
/// Gets the <see cref="CompilationResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The <see cref="IFileInfo"/> for the Razor file that was compiled.</param>
|
||||
/// <param name="compilationContent">The generated C# content to be compiled.</param>
|
||||
/// <param name="messages">The sequence of failure messages encountered during compilation.</param>
|
||||
/// <returns>A CompilationResult instance representing a failure.</returns>
|
||||
public static CompilationResult Failed([NotNull] IFileInfo file,
|
||||
[NotNull] string compilationContent,
|
||||
[NotNull] IEnumerable<CompilationMessage> messages)
|
||||
/// <returns>The current <see cref="CompilationResult"/> instance.</returns>
|
||||
/// <exception cref="CompilationFailedException">Thrown if compilation failed.</exception>
|
||||
public CompilationResult EnsureSuccessful()
|
||||
{
|
||||
if (CompilationFailure != null)
|
||||
{
|
||||
throw new CompilationFailedException(CompilationFailure);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CompilationResult"/> for a failed compilation.
|
||||
/// </summary>
|
||||
/// <param name="compilationFailure">The <see cref="ICompilationFailure"/> produced from parsing or
|
||||
/// compiling the Razor file.</param>
|
||||
/// <returns>A <see cref="CompilationResult"/> instance for a failed compilation.</returns>
|
||||
public static CompilationResult Failed([NotNull] ICompilationFailure compilationFailure)
|
||||
{
|
||||
return new CompilationResult
|
||||
{
|
||||
File = file,
|
||||
CompiledContent = compilationContent,
|
||||
Messages = messages,
|
||||
CompilationFailure = compilationFailure
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CompilationResult"/> that represents a success in compilation.
|
||||
/// Creates a <see cref="CompilationResult"/> for a successful compilation.
|
||||
/// </summary>
|
||||
/// <param name="type">The compiled type.</param>
|
||||
/// <returns>A CompilationResult instance representing a success.</returns>
|
||||
/// <returns>A <see cref="CompilationResult"/> instance for a successful compilation.</returns>
|
||||
public static CompilationResult Successful([NotNull] Type type)
|
||||
{
|
||||
return new CompilationResult
|
||||
|
|
@ -102,31 +77,5 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
CompiledType = type
|
||||
};
|
||||
}
|
||||
|
||||
private CompilationFailedException CreateCompilationFailedException()
|
||||
{
|
||||
var fileContent = ReadContent(File);
|
||||
var compilationFailure = new CompilationFailure(FilePath, fileContent, CompiledContent, Messages);
|
||||
return new CompilationFailedException(compilationFailure);
|
||||
}
|
||||
|
||||
private static string ReadContent(IFileInfo file)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = file.CreateReadStream())
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Don't throw if reading the file fails.
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
string normalizedPath,
|
||||
Func<RelativeFileInfo, CompilationResult> compile)
|
||||
{
|
||||
var compilationResult = compile(file);
|
||||
var compilationResult = compile(file).EnsureSuccessful();
|
||||
|
||||
// Concurrent addition to MemoryCache with the same key result in safe race.
|
||||
var cacheEntry = _cache.Set(normalizedPath,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -13,11 +11,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <summary>
|
||||
/// Compiles content and returns the result of compilation.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The <see cref="IFileInfo"/> for the Razor file that was compiled.</param>
|
||||
/// <param name="fileInfo">The <see cref="RelativeFileInfo"/> for the Razor file that was compiled.</param>
|
||||
/// <param name="compilationContent">The generated C# content to be compiled.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="CompilationResult"/> representing the result of compilation.
|
||||
/// </returns>
|
||||
CompilationResult Compile(IFileInfo fileInfo, string compilationContent);
|
||||
CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Framework.Runtime;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ICompilationFailure"/> for Razor parse failures.
|
||||
/// </summary>
|
||||
public class RazorCompilationFailure : ICompilationFailure
|
||||
{
|
||||
/// <summary>Initializes a new instance of <see cref="RazorCompilationFailure"/>.</summary>
|
||||
/// <param name="sourceFilePath">The path of the Razor source file that was compiled.</param>
|
||||
/// <param name="sourceFileContent">The contents of the Razor source file.</param>
|
||||
/// <param name="messages">A sequence of <see cref="ICompilationMessage"/> encountered
|
||||
/// during compilation.</param>
|
||||
public RazorCompilationFailure(
|
||||
[NotNull] string sourceFilePath,
|
||||
[NotNull] string sourceFileContent,
|
||||
[NotNull] IEnumerable<RazorCompilationMessage> messages)
|
||||
{
|
||||
SourceFilePath = sourceFilePath;
|
||||
SourceFileContent = sourceFileContent;
|
||||
Messages = messages;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SourceFilePath { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SourceFileContent { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string CompiledContent { get; } = null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ICompilationMessage> Messages { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.Runtime;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ICompilationMessage"/> for a <see cref="RazorError"/> encountered during parsing.
|
||||
/// </summary>
|
||||
public class RazorCompilationMessage : ICompilationMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="RazorCompilationMessage"/> with the specified message.
|
||||
/// </summary>
|
||||
/// <param name="razorError">A <see cref="RazorError"/>.</param>
|
||||
/// <param name="sourceFilePath">The path of the Razor source file that was parsed.</param>
|
||||
public RazorCompilationMessage(
|
||||
[NotNull] RazorError razorError,
|
||||
string sourceFilePath)
|
||||
{
|
||||
SourceFilePath = sourceFilePath;
|
||||
Message = razorError.Message;
|
||||
|
||||
var location = razorError.Location;
|
||||
FormattedMessage =
|
||||
$"{sourceFilePath} ({location.LineIndex},{location.CharacterIndex}) {razorError.Message}";
|
||||
|
||||
StartColumn = location.CharacterIndex;
|
||||
StartLine = location.LineIndex;
|
||||
EndColumn = location.CharacterIndex + razorError.Length;
|
||||
EndLine = location.LineIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a message produced from compilation.
|
||||
/// </summary>
|
||||
public string Message { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int StartColumn { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int StartLine { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int EndColumn { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int EndLine { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SourceFilePath { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string FormattedMessage { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
// All Razor diagnostics are errors
|
||||
public CompilationMessageSeverity Severity { get; } = CompilationMessageSeverity.Error;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> representation of this instance of <see cref="RazorCompilationMessage"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="string"/> representing this <see cref="RazorCompilationMessage"/> instance.</returns>
|
||||
/// <remarks>Returns same value as <see cref="Message"/>.</remarks>
|
||||
public override string ToString()
|
||||
{
|
||||
return FormattedMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,12 +60,12 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CompilationResult Compile([NotNull] IFileInfo fileInfo, [NotNull] string compilationContent)
|
||||
public CompilationResult Compile([NotNull] RelativeFileInfo fileInfo, [NotNull] string compilationContent)
|
||||
{
|
||||
// The path passed to SyntaxTreeGenerator.Generate is used by the compiler to generate symbols (pdb) that
|
||||
// map to the source file. If a file does not exist on a physical file system, PhysicalPath will be null.
|
||||
// This prevents files that exist in a non-physical file system from being debugged.
|
||||
var path = fileInfo.PhysicalPath ?? fileInfo.Name;
|
||||
var path = fileInfo.FileInfo.PhysicalPath ?? fileInfo.RelativePath;
|
||||
var compilationSettings = _compilerOptionsProvider.GetCompilationSettings(_environment);
|
||||
var syntaxTree = SyntaxTreeGenerator.Generate(compilationContent,
|
||||
path,
|
||||
|
|
@ -98,14 +98,15 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
if (!result.Success)
|
||||
{
|
||||
var formatter = new DiagnosticFormatter();
|
||||
var failures = result.Diagnostics.Where(IsError);
|
||||
var compilationFailure = new RoslynCompilationFailure(failures)
|
||||
{
|
||||
CompiledContent = compilationContent,
|
||||
SourceFileContent = ReadFileContentsSafely(fileInfo.FileInfo),
|
||||
SourceFilePath = fileInfo.RelativePath
|
||||
};
|
||||
|
||||
var messages = result.Diagnostics
|
||||
.Where(IsError)
|
||||
.Select(d => GetCompilationMessage(formatter, d))
|
||||
.ToList();
|
||||
|
||||
return CompilationResult.Failed(fileInfo, compilationContent, messages);
|
||||
return CompilationResult.Failed(compilationFailure);
|
||||
}
|
||||
|
||||
Assembly assembly;
|
||||
|
|
@ -215,21 +216,25 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
return metadata.GetReference();
|
||||
}
|
||||
|
||||
private static CompilationMessage GetCompilationMessage(DiagnosticFormatter formatter, Diagnostic diagnostic)
|
||||
{
|
||||
var lineSpan = diagnostic.Location.GetMappedLineSpan();
|
||||
return new CompilationMessage(formatter.Format(diagnostic),
|
||||
startColumn: lineSpan.StartLinePosition.Character,
|
||||
startLine: lineSpan.StartLinePosition.Line,
|
||||
endColumn: lineSpan.EndLinePosition.Character,
|
||||
endLine: lineSpan.EndLinePosition.Line);
|
||||
}
|
||||
|
||||
private static bool IsError(Diagnostic diagnostic)
|
||||
{
|
||||
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
|
||||
}
|
||||
|
||||
|
||||
private static string ReadFileContentsSafely(IFileInfo fileInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore any failures
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Error compiling page at '{0}'.
|
||||
/// One or more compilation failures occured:
|
||||
/// </summary>
|
||||
internal static string CompilationFailed
|
||||
{
|
||||
|
|
@ -35,11 +35,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Error compiling page at '{0}'.
|
||||
/// One or more compilation failures occured:
|
||||
/// </summary>
|
||||
internal static string FormatCompilationFailed(object p0)
|
||||
internal static string FormatCompilationFailed()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("CompilationFailed"), p0);
|
||||
return GetString("CompilationFailed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.AspNet.Razor;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
|
|
@ -35,16 +37,32 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
if (!results.Success)
|
||||
{
|
||||
var messages = results.ParserErrors
|
||||
.Select(parseError =>
|
||||
new CompilationMessage(parseError.Message,
|
||||
parseError.Location.CharacterIndex,
|
||||
parseError.Location.LineIndex,
|
||||
parseError.Location.CharacterIndex + parseError.Length,
|
||||
parseError.Location.LineIndex));
|
||||
return CompilationResult.Failed(file.FileInfo, results.GeneratedCode, messages);
|
||||
.Select(parseError => new RazorCompilationMessage(parseError, file.RelativePath));
|
||||
var failure = new RazorCompilationFailure(
|
||||
file.RelativePath,
|
||||
ReadFileContentsSafely(file.FileInfo),
|
||||
messages);
|
||||
|
||||
return CompilationResult.Failed(failure);
|
||||
}
|
||||
|
||||
return _compilationService.Compile(file.FileInfo, results.GeneratedCode);
|
||||
return _compilationService.Compile(file, results.GeneratedCode);
|
||||
}
|
||||
|
||||
private static string ReadFileContentsSafely(IFileInfo fileInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore any failures
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@
|
|||
<value>Value cannot be null or empty.</value>
|
||||
</data>
|
||||
<data name="CompilationFailed" xml:space="preserve">
|
||||
<value>Error compiling page at '{0}'.</value>
|
||||
<value>One or more compilation failures occured:</value>
|
||||
</data>
|
||||
<data name="FlushPointCannotBeInvoked" xml:space="preserve">
|
||||
<value>'{0}' cannot be invoked when a Layout page is set to be executed.</value>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.Framework.Runtime;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -12,32 +10,18 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
public class CompilationResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void FailedResult_ThrowsWhenAccessingCompiledType()
|
||||
public void EnsureSuccessful_ThrowsIfCompilationFailed()
|
||||
{
|
||||
// Arrange
|
||||
var expected = @"Error compiling page at 'myfile'.";
|
||||
var originalContent = "Original file content";
|
||||
var fileInfo = new Mock<IFileInfo>();
|
||||
fileInfo.SetupGet(f => f.PhysicalPath)
|
||||
.Returns("myfile");
|
||||
var contentBytes = Encoding.UTF8.GetBytes(originalContent);
|
||||
fileInfo.Setup(f => f.CreateReadStream())
|
||||
.Returns(new MemoryStream(contentBytes));
|
||||
var messages = new[]
|
||||
{
|
||||
new CompilationMessage("hello", 1, 1, 2, 2),
|
||||
new CompilationMessage("world", 3, 3, 4, 3)
|
||||
};
|
||||
var result = CompilationResult.Failed(fileInfo.Object,
|
||||
"<h1>hello world</h1>",
|
||||
messages);
|
||||
var compilationFailure = Mock.Of<ICompilationFailure>();
|
||||
var result = CompilationResult.Failed(compilationFailure);
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<CompilationFailedException>(() => result.CompiledType);
|
||||
Assert.Equal(expected, ex.Message);
|
||||
var compilationFailure = Assert.Single(ex.CompilationFailures);
|
||||
Assert.Equal(originalContent, compilationFailure.SourceFileContent);
|
||||
Assert.Equal(messages, compilationFailure.Messages);
|
||||
Assert.Null(result.CompiledType);
|
||||
Assert.Same(compilationFailure, result.CompilationFailure);
|
||||
var exception = Assert.Throws<CompilationFailedException>(() => result.EnsureSuccessful());
|
||||
Assert.Collection(exception.CompilationFailures,
|
||||
failure => Assert.Same(compilationFailure, failure));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Assert
|
||||
Assert.NotSame(CompilerCacheResult.FileNotFound, result);
|
||||
var actual = result.CompilationResult;
|
||||
var actual = Assert.IsType<UncachedCompilationResult>(result.CompilationResult);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Same(expected, actual);
|
||||
Assert.Equal("hello world", actual.CompiledContent);
|
||||
|
|
@ -541,23 +541,18 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Act
|
||||
cache.GetOrAdd("test", _ => uncachedResult);
|
||||
var result1 = cache.GetOrAdd("test", _ => uncachedResult);
|
||||
var result2 = cache.GetOrAdd("test", _ => uncachedResult);
|
||||
var result1 = cache.GetOrAdd("test", _ => { throw new Exception("shouldn't be called."); });
|
||||
var result2 = cache.GetOrAdd("test", _ => { throw new Exception("shouldn't be called."); });
|
||||
|
||||
// Assert
|
||||
Assert.NotSame(CompilerCacheResult.FileNotFound, result1);
|
||||
Assert.NotSame(CompilerCacheResult.FileNotFound, result2);
|
||||
|
||||
var actual1 = result1.CompilationResult;
|
||||
var actual2 = result2.CompilationResult;
|
||||
var actual1 = Assert.IsType<CompilationResult>(result1.CompilationResult);
|
||||
var actual2 = Assert.IsType<CompilationResult>(result2.CompilationResult);
|
||||
Assert.NotSame(uncachedResult, actual1);
|
||||
Assert.NotSame(uncachedResult, actual2);
|
||||
var result = Assert.IsType<CompilationResult>(actual1);
|
||||
Assert.Null(actual1.CompiledContent);
|
||||
Assert.Same(type, actual1.CompiledType);
|
||||
|
||||
result = Assert.IsType<CompilationResult>(actual2);
|
||||
Assert.Null(actual2.CompiledContent);
|
||||
Assert.Same(type, actual2.CompiledType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath);
|
||||
fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");
|
||||
|
||||
var compiler = new Mock<ICompilationService>();
|
||||
compiler.Setup(c => c.Compile(fileInfo.Object, It.IsAny<string>()))
|
||||
compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny<string>()))
|
||||
.Returns(CompilationResult.Successful(typeof(RazorCompilationServiceTest)));
|
||||
|
||||
var razorService = new RazorCompilationService(compiler.Object, host.Object);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");
|
||||
|
||||
// Act
|
||||
razorService.Compile(relativeFileInfo);
|
||||
|
||||
|
|
@ -75,9 +75,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
var result = razorService.Compile(relativeFileInfo);
|
||||
|
||||
// Assert
|
||||
var ex = Assert.Throws<CompilationFailedException>(() => result.CompiledType);
|
||||
var failure = Assert.Single(ex.CompilationFailures);
|
||||
var message = Assert.Single(failure.Messages);
|
||||
Assert.NotNull(result.CompilationFailure);
|
||||
var message = Assert.Single(result.CompilationFailure.Messages);
|
||||
Assert.Equal("some message", message.Message);
|
||||
host.Verify();
|
||||
}
|
||||
|
|
@ -100,13 +99,13 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
var fileInfo = new Mock<IFileInfo>();
|
||||
fileInfo.Setup(f => f.CreateReadStream())
|
||||
.Returns(Stream.Null);
|
||||
var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");
|
||||
|
||||
var compilationResult = CompilationResult.Successful(typeof(object));
|
||||
var compiler = new Mock<ICompilationService>();
|
||||
compiler.Setup(c => c.Compile(fileInfo.Object, code))
|
||||
compiler.Setup(c => c.Compile(relativeFileInfo, code))
|
||||
.Returns(compilationResult)
|
||||
.Verifiable();
|
||||
var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml");
|
||||
var razorService = new RazorCompilationService(compiler.Object, host.Object);
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.Framework.Runtime;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -37,14 +38,126 @@ public class MyTestType {}";
|
|||
libraryManager,
|
||||
compilerOptionsProvider.Object,
|
||||
mvcRazorHost.Object);
|
||||
var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(new TestFileInfo { PhysicalPath = "SomePath" }, content);
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
var uncachedResult = Assert.IsType<UncachedCompilationResult>(result);
|
||||
Assert.Equal("MyTestType", result.CompiledType.Name);
|
||||
Assert.Equal(content, result.CompiledContent);
|
||||
Assert.Equal(content, uncachedResult.CompiledContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_ReturnsCompilationFailureWithRelativePath()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = "test file content";
|
||||
var content = @"this should fail";
|
||||
var applicationEnvironment = GetApplicationEnvironment();
|
||||
var accessor = GetLoadContextAccessor();
|
||||
var libraryManager = GetLibraryManager();
|
||||
|
||||
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
|
||||
compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||
applicationEnvironment.RuntimeFramework,
|
||||
applicationEnvironment.Configuration))
|
||||
.Returns(new CompilerOptions());
|
||||
var mvcRazorHost = Mock.Of<IMvcRazorHost>();
|
||||
|
||||
var compilationService = new RoslynCompilationService(applicationEnvironment,
|
||||
accessor,
|
||||
libraryManager,
|
||||
compilerOptionsProvider.Object,
|
||||
mvcRazorHost);
|
||||
var fileInfo = new TestFileInfo
|
||||
{
|
||||
Content = fileContent,
|
||||
PhysicalPath = "physical path"
|
||||
};
|
||||
var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CompilationResult>(result);
|
||||
Assert.Null(result.CompiledType);
|
||||
Assert.Equal(relativeFileInfo.RelativePath, result.CompilationFailure.SourceFilePath);
|
||||
Assert.Equal(fileContent, result.CompilationFailure.SourceFileContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_ReturnsApplicationRelativePath_IfPhyicalPathIsNotSpecified()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = "file content";
|
||||
var content = @"this should fail";
|
||||
var applicationEnvironment = GetApplicationEnvironment();
|
||||
var accessor = GetLoadContextAccessor();
|
||||
var libraryManager = GetLibraryManager();
|
||||
|
||||
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
|
||||
compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||
applicationEnvironment.RuntimeFramework,
|
||||
applicationEnvironment.Configuration))
|
||||
.Returns(new CompilerOptions());
|
||||
var mvcRazorHost = Mock.Of<IMvcRazorHost>();
|
||||
|
||||
var compilationService = new RoslynCompilationService(applicationEnvironment,
|
||||
accessor,
|
||||
libraryManager,
|
||||
compilerOptionsProvider.Object,
|
||||
mvcRazorHost);
|
||||
var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { Content = fileContent },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CompilationResult>(result);
|
||||
Assert.Null(result.CompiledType);
|
||||
Assert.Equal("some-relative-path", result.CompilationFailure.SourceFilePath);
|
||||
Assert.Equal(fileContent, result.CompilationFailure.SourceFileContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_DoesNotThrow_IfFileCannotBeRead()
|
||||
{
|
||||
// Arrange
|
||||
var content = @"this should fail";
|
||||
var applicationEnvironment = GetApplicationEnvironment();
|
||||
var accessor = GetLoadContextAccessor();
|
||||
var libraryManager = GetLibraryManager();
|
||||
|
||||
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
|
||||
compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||
applicationEnvironment.RuntimeFramework,
|
||||
applicationEnvironment.Configuration))
|
||||
.Returns(new CompilerOptions());
|
||||
var mvcRazorHost = Mock.Of<IMvcRazorHost>();
|
||||
|
||||
var compilationService = new RoslynCompilationService(applicationEnvironment,
|
||||
accessor,
|
||||
libraryManager,
|
||||
compilerOptionsProvider.Object,
|
||||
mvcRazorHost);
|
||||
var mockFileInfo = new Mock<IFileInfo>();
|
||||
mockFileInfo.Setup(f => f.CreateReadStream())
|
||||
.Throws(new Exception());
|
||||
var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, "some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CompilationResult>(result);
|
||||
Assert.Null(result.CompiledType);
|
||||
Assert.Equal("some-relative-path", result.CompilationFailure.SourceFilePath);
|
||||
Assert.Null(result.CompilationFailure.SourceFileContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -76,9 +189,11 @@ public class MyNonCustomDefinedClass {}
|
|||
libraryManager,
|
||||
compilerOptionsProvider.Object,
|
||||
mvcRazorHost.Object);
|
||||
var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(new TestFileInfo { PhysicalPath = "SomePath" }, content);
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.CompiledType);
|
||||
|
|
@ -111,8 +226,11 @@ public class NotRazorPrefixType {}";
|
|||
compilerOptionsProvider.Object,
|
||||
mvcRazorHost.Object);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(new TestFileInfo { PhysicalPath = "SomePath" }, content);
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.CompiledType);
|
||||
|
|
|
|||
Loading…
Reference in New Issue