parent
2f46113556
commit
c942eab6e2
|
|
@ -12,8 +12,27 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
|||
/// <summary>
|
||||
/// An <see cref="ApplicationPart"/> backed by an <see cref="Assembly"/>.
|
||||
/// </summary>
|
||||
public class AssemblyPart : ApplicationPart, IApplicationPartTypeProvider, ICompilationReferencesProvider
|
||||
public class AssemblyPart :
|
||||
ApplicationPart,
|
||||
IApplicationPartTypeProvider,
|
||||
ICompilationReferencesProvider,
|
||||
IViewsProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the suffix for the view assembly.
|
||||
/// </summary>
|
||||
public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the namespace for the <see cref="ViewInfoContainer"/> type in the view assembly.
|
||||
/// </summary>
|
||||
public static readonly string ViewInfoContainerNamespace = "AspNetCore";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type name for the view collection type in the view assembly.
|
||||
/// </summary>
|
||||
public static readonly string ViewInfoContainerTypeName = "__PrecompiledViewCollection";
|
||||
|
||||
/// <summary>
|
||||
/// Initalizes a new <see cref="AssemblyPart"/> instance.
|
||||
/// </summary>
|
||||
|
|
@ -41,6 +60,27 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
|||
/// <inheritdoc />
|
||||
public IEnumerable<TypeInfo> Types => Assembly.DefinedTypes;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ViewInfo> Views
|
||||
{
|
||||
get
|
||||
{
|
||||
var precompiledAssemblyName = new AssemblyName(Assembly.FullName);
|
||||
precompiledAssemblyName.Name = precompiledAssemblyName.Name + PrecompiledViewsAssemblySuffix;
|
||||
|
||||
var typeName = $"{ViewInfoContainerNamespace}.{ViewInfoContainerTypeName},{precompiledAssemblyName}";
|
||||
var viewInfoContainerTypeName = Type.GetType(typeName);
|
||||
|
||||
if (viewInfoContainerTypeName == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var precompiledViews = (ViewInfoContainer)Activator.CreateInstance(viewInfoContainerTypeName);
|
||||
return precompiledViews.ViewInfos;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> GetReferencePaths()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes a sequence of views associated with an <see cref="ApplicationPart"/> .
|
||||
/// </summary>
|
||||
public interface IViewsProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the sequence of <see cref="ViewInfo"/>.
|
||||
/// </summary>
|
||||
IEnumerable<ViewInfo> Views { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides information for precompiled views.
|
||||
/// </summary>
|
||||
public class ViewInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="ViewInfo" />.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the view.</param>
|
||||
/// <param name="type">The view <see cref="System.Type"/>.</param>
|
||||
public ViewInfo(string path, Type type)
|
||||
{
|
||||
Path = path;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The path of the view.
|
||||
/// </summary>
|
||||
public string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The view <see cref="System.Type"/>.
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||
{
|
||||
/// <summary>
|
||||
/// A container for <see cref="ViewInfo"/> instances.
|
||||
/// </summary>
|
||||
public class ViewInfoContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="ViewInfos"/>.
|
||||
/// </summary>
|
||||
/// <param name="views">The sequence of <see cref="ViewInfo"/>.</param>
|
||||
public ViewInfoContainer(IReadOnlyList<ViewInfo> views)
|
||||
{
|
||||
ViewInfos = views;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IReadOnlyList{T}"/> of <see cref="ViewInfo"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ViewInfo> ViewInfos { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the <see cref="IMvcBuilder"/>. Implement this interface to enable design-time configuration
|
||||
/// (for instance during pre-compilation of views) of <see cref="IMvcBuilder"/>.
|
||||
/// </summary>
|
||||
public interface IDesignTimeMvcBuilderConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the <see cref="IMvcBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
void ConfigureMvc(IMvcBuilder builder);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||
{
|
||||
public class ViewsFeature
|
||||
{
|
||||
public IDictionary<string, Type> Views { get; } =
|
||||
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) .NET Foundation. 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 System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IApplicationFeatureProvider{TFeature}"/> for <see cref="ViewsFeature"/>.
|
||||
/// </summary>
|
||||
public class ViewsFeatureProvider : IApplicationFeatureProvider<ViewsFeature>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ViewsFeature feature)
|
||||
{
|
||||
foreach (var provider in parts.OfType<IViewsProvider>())
|
||||
{
|
||||
var precompiledViews = provider.Views;
|
||||
if (precompiledViews != null)
|
||||
{
|
||||
foreach (var viewInfo in precompiledViews)
|
||||
{
|
||||
feature.Views[viewInfo.Path] = viewInfo.Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,6 +72,11 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
builder.PartManager.FeatureProviders.Add(new MetadataReferenceFeatureProvider());
|
||||
}
|
||||
|
||||
if (!builder.PartManager.FeatureProviders.OfType<ViewsFeatureProvider>().Any())
|
||||
{
|
||||
builder.PartManager.FeatureProviders.Add(new ViewsFeatureProvider());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -127,6 +132,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
// Internal for testing.
|
||||
internal static void AddRazorViewEngineServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<CSharpCompiler>();
|
||||
services.TryAddSingleton<RazorReferenceManager>();
|
||||
// This caches compilation related details that are valid across the lifetime of the application.
|
||||
services.TryAddSingleton<ICompilationService, DefaultRoslynCompilationService>();
|
||||
|
||||
|
|
@ -165,7 +172,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
// creating the singleton RazorViewEngine instance.
|
||||
services.TryAddTransient<IRazorPageFactoryProvider, DefaultRazorPageFactoryProvider>();
|
||||
services.TryAddTransient<IRazorCompilationService, RazorCompilationService>();
|
||||
services.TryAddTransient<IMvcRazorHost,MvcRazorHost>();
|
||||
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
|
||||
|
||||
// This caches Razor page activation details that are valid for the lifetime of the application.
|
||||
services.TryAddSingleton<IRazorPageActivator, RazorPageActivator>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Emit;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
public class CSharpCompiler
|
||||
{
|
||||
private readonly CSharpCompilationOptions _compilationOptions;
|
||||
private readonly CSharpParseOptions _parseOptions;
|
||||
private readonly RazorReferenceManager _referenceManager;
|
||||
private readonly DebugInformationFormat _pdbFormat =
|
||||
#if NET451
|
||||
SymbolsUtility.SupportsFullPdbGeneration() ?
|
||||
DebugInformationFormat.Pdb :
|
||||
DebugInformationFormat.PortablePdb;
|
||||
#else
|
||||
DebugInformationFormat.PortablePdb;
|
||||
#endif
|
||||
|
||||
public CSharpCompiler(RazorReferenceManager manager, IOptions<RazorViewEngineOptions> optionsAccessor)
|
||||
{
|
||||
_referenceManager = manager;
|
||||
_compilationOptions = optionsAccessor.Value.CompilationOptions;
|
||||
_parseOptions = optionsAccessor.Value.ParseOptions;
|
||||
EmitOptions = new EmitOptions(debugInformationFormat: _pdbFormat);
|
||||
}
|
||||
|
||||
public EmitOptions EmitOptions { get; }
|
||||
|
||||
public SyntaxTree CreateSyntaxTree(SourceText sourceText)
|
||||
{
|
||||
return CSharpSyntaxTree.ParseText(
|
||||
sourceText,
|
||||
options: _parseOptions);
|
||||
}
|
||||
|
||||
public CSharpCompilation CreateCompilation(string assemblyName)
|
||||
{
|
||||
return CSharpCompilation.Create(
|
||||
assemblyName,
|
||||
options: _compilationOptions,
|
||||
references: _referenceManager.CompilationReferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,22 +42,22 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="CompilerCache"/> populated with precompiled views
|
||||
/// specified by <paramref name="precompiledViews"/>.
|
||||
/// specified by <paramref name="views"/>.
|
||||
/// </summary>
|
||||
/// <param name="fileProvider"><see cref="IFileProvider"/> used to locate Razor views.</param>
|
||||
/// <param name="precompiledViews">A mapping of application relative paths of view to the precompiled view
|
||||
/// <see cref="Type"/>s.</param>
|
||||
/// <param name="views">A mapping of application relative paths of view to <see cref="Type"/>s that
|
||||
/// have already been compiled.</param>
|
||||
public CompilerCache(
|
||||
IFileProvider fileProvider,
|
||||
IDictionary<string, Type> precompiledViews)
|
||||
IDictionary<string, Type> views)
|
||||
: this(fileProvider)
|
||||
{
|
||||
if (precompiledViews == null)
|
||||
if (views == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(precompiledViews));
|
||||
throw new ArgumentNullException(nameof(views));
|
||||
}
|
||||
|
||||
foreach (var item in precompiledViews)
|
||||
foreach (var item in views)
|
||||
{
|
||||
var cacheEntry = new CompilerCacheResult(item.Key, new CompilationResult(item.Value));
|
||||
_cache.Set(GetNormalizedPath(item.Key), Task.FromResult(cacheEntry));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
|
|
@ -13,10 +14,15 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="applicationPartManager">The <see cref="ApplicationPartManager" /></param>
|
||||
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
|
||||
public DefaultCompilerCacheProvider(IRazorViewEngineFileProviderAccessor fileProviderAccessor)
|
||||
public DefaultCompilerCacheProvider(
|
||||
ApplicationPartManager applicationPartManager,
|
||||
IRazorViewEngineFileProviderAccessor fileProviderAccessor)
|
||||
{
|
||||
Cache = new CompilerCache(fileProviderAccessor.FileProvider);
|
||||
var feature = new ViewsFeature();
|
||||
applicationPartManager.PopulateFeature(feature);
|
||||
Cache = new CompilerCache(fileProviderAccessor.FileProvider, feature.Views);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -8,13 +8,10 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Emit;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -33,59 +30,31 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
// error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive
|
||||
// or an assembly reference?)
|
||||
private const string CS0246 = nameof(CS0246);
|
||||
private readonly DebugInformationFormat _pdbFormat =
|
||||
#if NET451
|
||||
SymbolsUtility.SupportsFullPdbGeneration() ?
|
||||
DebugInformationFormat.Pdb :
|
||||
DebugInformationFormat.PortablePdb;
|
||||
#else
|
||||
DebugInformationFormat.PortablePdb;
|
||||
#endif
|
||||
private readonly ApplicationPartManager _partManager;
|
||||
|
||||
private readonly CSharpCompiler _compiler;
|
||||
private readonly IFileProvider _fileProvider;
|
||||
private readonly Action<RoslynCompilationContext> _compilationCallback;
|
||||
private readonly CSharpParseOptions _parseOptions;
|
||||
private readonly CSharpCompilationOptions _compilationOptions;
|
||||
private readonly IList<MetadataReference> _additionalMetadataReferences;
|
||||
private readonly ILogger _logger;
|
||||
private object _compilationReferencesLock = new object();
|
||||
private bool _compilationReferencesInitialized;
|
||||
private IList<MetadataReference> _compilationReferences;
|
||||
private readonly Action<RoslynCompilationContext> _compilationCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Initalizes a new instance of the <see cref="DefaultRoslynCompilationService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="partManager">The <see cref="ApplicationPartManager"/>.</param>
|
||||
/// <param name="compiler">The <see cref="CSharpCompiler"/>.</param>
|
||||
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
|
||||
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public DefaultRoslynCompilationService(
|
||||
ApplicationPartManager partManager,
|
||||
IOptions<RazorViewEngineOptions> optionsAccessor,
|
||||
CSharpCompiler compiler,
|
||||
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
|
||||
IOptions<RazorViewEngineOptions> optionsAccessor,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_partManager = partManager;
|
||||
_compiler = compiler;
|
||||
_fileProvider = fileProviderAccessor.FileProvider;
|
||||
_compilationCallback = optionsAccessor.Value.CompilationCallback;
|
||||
_parseOptions = optionsAccessor.Value.ParseOptions;
|
||||
_compilationOptions = optionsAccessor.Value.CompilationOptions;
|
||||
_additionalMetadataReferences = optionsAccessor.Value.AdditionalCompilationReferences;
|
||||
_logger = loggerFactory.CreateLogger<DefaultRoslynCompilationService>();
|
||||
}
|
||||
|
||||
private IList<MetadataReference> CompilationReferences
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _compilationReferences,
|
||||
ref _compilationReferencesInitialized,
|
||||
ref _compilationReferencesLock,
|
||||
GetCompilationReferences);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
|
||||
{
|
||||
|
|
@ -100,28 +69,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
}
|
||||
|
||||
_logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath);
|
||||
|
||||
var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;
|
||||
|
||||
var assemblyName = Path.GetRandomFileName();
|
||||
|
||||
var sourceText = SourceText.From(compilationContent, Encoding.UTF8);
|
||||
var syntaxTree = CSharpSyntaxTree.ParseText(
|
||||
sourceText,
|
||||
path: assemblyName,
|
||||
options: _parseOptions);
|
||||
|
||||
var compilation = CSharpCompilation.Create(
|
||||
assemblyName,
|
||||
options: _compilationOptions,
|
||||
syntaxTrees: new[] { syntaxTree },
|
||||
references: CompilationReferences);
|
||||
|
||||
compilation = Rewrite(compilation);
|
||||
|
||||
var compilationContext = new RoslynCompilationContext(compilation);
|
||||
_compilationCallback(compilationContext);
|
||||
compilation = compilationContext.Compilation;
|
||||
var compilation = CreateCompilation(compilationContent, assemblyName);
|
||||
|
||||
using (var assemblyStream = new MemoryStream())
|
||||
{
|
||||
|
|
@ -130,7 +81,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
var result = compilation.Emit(
|
||||
assemblyStream,
|
||||
pdbStream,
|
||||
options: new EmitOptions(debugInformationFormat: _pdbFormat));
|
||||
options: _compiler.EmitOptions);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
|
|
@ -144,8 +95,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
assemblyStream.Seek(0, SeekOrigin.Begin);
|
||||
pdbStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var assembly = LoadStream(assemblyStream, pdbStream);
|
||||
var assembly = LoadAssembly(assemblyStream, pdbStream);
|
||||
var type = assembly.GetExportedTypes().FirstOrDefault(a => !a.IsNested);
|
||||
|
||||
_logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp);
|
||||
|
||||
return new CompilationResult(type);
|
||||
|
|
@ -153,50 +105,19 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sequence of <see cref="MetadataReference"/> instances used for compilation.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="MetadataReference"/> instances.</returns>
|
||||
protected virtual IList<MetadataReference> GetCompilationReferences()
|
||||
private CSharpCompilation CreateCompilation(string compilationContent, string assemblyName)
|
||||
{
|
||||
var feature = new MetadataReferenceFeature();
|
||||
_partManager.PopulateFeature(feature);
|
||||
var applicationReferences = feature.MetadataReferences;
|
||||
var sourceText = SourceText.From(compilationContent, Encoding.UTF8);
|
||||
var syntaxTree = _compiler.CreateSyntaxTree(sourceText).WithFilePath(assemblyName);
|
||||
var compilation = _compiler
|
||||
.CreateCompilation(assemblyName)
|
||||
.AddSyntaxTrees(syntaxTree);
|
||||
compilation = ExpressionRewriter.Rewrite(compilation);
|
||||
|
||||
if (_additionalMetadataReferences.Count == 0)
|
||||
{
|
||||
return applicationReferences;
|
||||
}
|
||||
|
||||
var compilationReferences = new List<MetadataReference>(applicationReferences.Count + _additionalMetadataReferences.Count);
|
||||
compilationReferences.AddRange(applicationReferences);
|
||||
compilationReferences.AddRange(_additionalMetadataReferences);
|
||||
|
||||
return compilationReferences;
|
||||
}
|
||||
|
||||
private Assembly LoadStream(MemoryStream assemblyStream, MemoryStream pdbStream)
|
||||
{
|
||||
#if NET451
|
||||
return Assembly.Load(assemblyStream.ToArray(), pdbStream.ToArray());
|
||||
#else
|
||||
return System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(assemblyStream, pdbStream);
|
||||
#endif
|
||||
}
|
||||
|
||||
private CSharpCompilation Rewrite(CSharpCompilation compilation)
|
||||
{
|
||||
var rewrittenTrees = new List<SyntaxTree>();
|
||||
foreach (var tree in compilation.SyntaxTrees)
|
||||
{
|
||||
var semanticModel = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
|
||||
var rewriter = new ExpressionRewriter(semanticModel);
|
||||
|
||||
var rewrittenTree = tree.WithRootAndOptions(rewriter.Visit(tree.GetRoot()), tree.Options);
|
||||
rewrittenTrees.Add(rewrittenTree);
|
||||
}
|
||||
|
||||
return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(rewrittenTrees);
|
||||
var compilationContext = new RoslynCompilationContext(compilation);
|
||||
_compilationCallback(compilationContext);
|
||||
compilation = compilationContext.Compilation;
|
||||
return compilation;
|
||||
}
|
||||
|
||||
// Internal for unit testing
|
||||
|
|
@ -265,6 +186,17 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
|
||||
}
|
||||
|
||||
public static Assembly LoadAssembly(MemoryStream assemblyStream, MemoryStream pdbStream)
|
||||
{
|
||||
var assembly =
|
||||
#if NET451
|
||||
Assembly.Load(assemblyStream.ToArray(), pdbStream.ToArray());
|
||||
#else
|
||||
System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(assemblyStream, pdbStream);
|
||||
#endif
|
||||
return assembly;
|
||||
}
|
||||
|
||||
private static string ReadFileContentsSafely(IFileProvider fileProvider, string filePath)
|
||||
{
|
||||
var fileInfo = fileProvider.GetFileInfo(filePath);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
|
|
@ -32,6 +31,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
private List<KeyValuePair<SimpleLambdaExpressionSyntax, IdentifierNameSyntax>> Expressions { get; }
|
||||
|
||||
public static CSharpCompilation Rewrite(CSharpCompilation compilation)
|
||||
{
|
||||
var rewrittenTrees = new List<SyntaxTree>();
|
||||
foreach (var tree in compilation.SyntaxTrees)
|
||||
{
|
||||
var semanticModel = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
|
||||
var rewriter = new ExpressionRewriter(semanticModel);
|
||||
|
||||
var rewrittenTree = tree.WithRootAndOptions(rewriter.Visit(tree.GetRoot()), tree.Options);
|
||||
rewrittenTrees.Add(rewrittenTree);
|
||||
}
|
||||
|
||||
return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(rewrittenTrees);
|
||||
}
|
||||
|
||||
public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
|
||||
{
|
||||
if (IsInsideClass)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) .NET Foundation. 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 System.Threading;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
public class RazorReferenceManager
|
||||
{
|
||||
private readonly ApplicationPartManager _partManager;
|
||||
private readonly IList<MetadataReference> _additionalMetadataReferences;
|
||||
private object _compilationReferencesLock = new object();
|
||||
private bool _compilationReferencesInitialized;
|
||||
private IList<MetadataReference> _compilationReferences;
|
||||
|
||||
public RazorReferenceManager(
|
||||
ApplicationPartManager partManager,
|
||||
IOptions<RazorViewEngineOptions> optionsAccessor)
|
||||
{
|
||||
_partManager = partManager;
|
||||
_additionalMetadataReferences = optionsAccessor.Value.AdditionalCompilationReferences;
|
||||
}
|
||||
|
||||
public IList<MetadataReference> CompilationReferences
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _compilationReferences,
|
||||
ref _compilationReferencesInitialized,
|
||||
ref _compilationReferencesLock,
|
||||
GetCompilationReferences);
|
||||
}
|
||||
}
|
||||
|
||||
private IList<MetadataReference> GetCompilationReferences()
|
||||
{
|
||||
var feature = new MetadataReferenceFeature();
|
||||
_partManager.PopulateFeature(feature);
|
||||
var applicationReferences = feature.MetadataReferences;
|
||||
|
||||
if (_additionalMetadataReferences.Count == 0)
|
||||
{
|
||||
return applicationReferences;
|
||||
}
|
||||
|
||||
var compilationReferences = new List<MetadataReference>(applicationReferences.Count + _additionalMetadataReferences.Count);
|
||||
compilationReferences.AddRange(applicationReferences);
|
||||
compilationReferences.AddRange(_additionalMetadataReferences);
|
||||
|
||||
return compilationReferences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
|
||||
{
|
||||
public class ViewsFeatureProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void PopulateFeature_ReturnsEmptySequenceIfNoAssemblyPartHasViewAssembly()
|
||||
{
|
||||
// Arrange
|
||||
var applicationPartManager = new ApplicationPartManager();
|
||||
applicationPartManager.ApplicationParts.Add(
|
||||
new AssemblyPart(typeof(ViewsFeatureProviderTest).GetTypeInfo().Assembly));
|
||||
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
|
||||
var feature = new MetadataReferenceFeature();
|
||||
|
||||
// Act
|
||||
applicationPartManager.PopulateFeature(feature);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(feature.MetadataReferences);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PopulateFeature_ReturnsViewsFromAllAvailableApplicationParts()
|
||||
{
|
||||
// Arrange
|
||||
var applicationPart1 = new Mock<ApplicationPart>();
|
||||
var viewsProvider1 = applicationPart1
|
||||
.As<IViewsProvider>()
|
||||
.SetupGet(p => p.Views)
|
||||
.Returns(new[]
|
||||
{
|
||||
new ViewInfo("/Views/test/Index.cshtml", typeof(object))
|
||||
});
|
||||
var applicationPart2 = new Mock<ApplicationPart>();
|
||||
var viewsProvider2 = applicationPart2
|
||||
.As<IViewsProvider>()
|
||||
.SetupGet(p => p.Views)
|
||||
.Returns(new[]
|
||||
{
|
||||
new ViewInfo("/Areas/Admin/Views/Index.cshtml", typeof(string)),
|
||||
new ViewInfo("/Areas/Admin/Views/About.cshtml", typeof(int))
|
||||
});
|
||||
|
||||
|
||||
var applicationPartManager = new ApplicationPartManager();
|
||||
applicationPartManager.ApplicationParts.Add(applicationPart1.Object);
|
||||
applicationPartManager.ApplicationParts.Add(applicationPart2.Object);
|
||||
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
|
||||
var feature = new MetadataReferenceFeature();
|
||||
|
||||
// Act
|
||||
applicationPartManager.PopulateFeature(feature);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(feature.MetadataReferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
// 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.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
|
|
@ -297,34 +295,6 @@ public class MyNonCustomDefinedClass {}
|
|||
Assert.NotNull(result.CompiledType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCompilationReferences_CombinesApplicationPartAndOptionMetadataReferences()
|
||||
{
|
||||
// Arrange
|
||||
var options = new RazorViewEngineOptions();
|
||||
var objectAssemblyLocation = typeof(object).GetTypeInfo().Assembly.Location;
|
||||
var objectAssemblyMetadataReference = MetadataReference.CreateFromFile(objectAssemblyLocation);
|
||||
options.AdditionalCompilationReferences.Add(objectAssemblyMetadataReference);
|
||||
var applicationPartManager = GetApplicationPartManager();
|
||||
var compilationService = new TestRoslynCompilationService(applicationPartManager, options);
|
||||
var feature = new MetadataReferenceFeature();
|
||||
applicationPartManager.PopulateFeature(feature);
|
||||
var partReferences = feature.MetadataReferences;
|
||||
var expectedReferences = new List<MetadataReference>();
|
||||
expectedReferences.AddRange(partReferences);
|
||||
expectedReferences.Add(objectAssemblyMetadataReference);
|
||||
var expectedReferenceDisplays = expectedReferences.Select(reference => reference.Display);
|
||||
|
||||
// Act
|
||||
var references = compilationService.GetCompilationReferencesPublic();
|
||||
var referenceDisplays = references.Select(reference => reference.Display);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(references);
|
||||
Assert.NotEmpty(references);
|
||||
Assert.Equal(expectedReferenceDisplays, referenceDisplays);
|
||||
}
|
||||
|
||||
private static DiagnosticDescriptor GetDiagnosticDescriptor(string messageFormat)
|
||||
{
|
||||
return new DiagnosticDescriptor(
|
||||
|
|
@ -377,22 +347,15 @@ public class MyNonCustomDefinedClass {}
|
|||
{
|
||||
partManager = partManager ?? GetApplicationPartManager();
|
||||
options = options ?? GetOptions();
|
||||
var optionsAccessor = GetAccessor(options);
|
||||
var referenceManager = new RazorReferenceManager(partManager, optionsAccessor);
|
||||
var compiler = new CSharpCompiler(referenceManager, optionsAccessor);
|
||||
|
||||
return new DefaultRoslynCompilationService(
|
||||
partManager,
|
||||
GetAccessor(options),
|
||||
compiler,
|
||||
GetFileProviderAccessor(fileProvider),
|
||||
optionsAccessor,
|
||||
NullLoggerFactory.Instance);
|
||||
}
|
||||
|
||||
private class TestRoslynCompilationService : DefaultRoslynCompilationService
|
||||
{
|
||||
public TestRoslynCompilationService(ApplicationPartManager partManager, RazorViewEngineOptions options)
|
||||
: base(partManager, GetAccessor(options), GetFileProviderAccessor(), NullLoggerFactory.Instance)
|
||||
{
|
||||
}
|
||||
|
||||
public IList<MetadataReference> GetCompilationReferencesPublic() => GetCompilationReferences();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Test.Internal
|
||||
{
|
||||
public class ReferenceManagerTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetCompilationReferences_CombinesApplicationPartAndOptionMetadataReferences()
|
||||
{
|
||||
// Arrange
|
||||
var options = new RazorViewEngineOptions();
|
||||
var objectAssemblyLocation = typeof(object).GetTypeInfo().Assembly.Location;
|
||||
var objectAssemblyMetadataReference = MetadataReference.CreateFromFile(objectAssemblyLocation);
|
||||
options.AdditionalCompilationReferences.Add(objectAssemblyMetadataReference);
|
||||
|
||||
var applicationPartManager = GetApplicationPartManager();
|
||||
var feature = new MetadataReferenceFeature();
|
||||
applicationPartManager.PopulateFeature(feature);
|
||||
var partReferences = feature.MetadataReferences;
|
||||
var expectedReferenceDisplays = partReferences
|
||||
.Concat(new[] { objectAssemblyMetadataReference })
|
||||
.Select(r => r.Display);
|
||||
var referenceManager = new RazorReferenceManager(applicationPartManager, GetAccessor(options));
|
||||
|
||||
// Act
|
||||
var references = referenceManager.CompilationReferences;
|
||||
var referenceDisplays = references.Select(reference => reference.Display);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedReferenceDisplays, referenceDisplays);
|
||||
}
|
||||
|
||||
private static ApplicationPartManager GetApplicationPartManager()
|
||||
{
|
||||
var applicationPartManager = new ApplicationPartManager();
|
||||
var assembly = typeof(DefaultRoslynCompilationServiceTest).GetTypeInfo().Assembly;
|
||||
applicationPartManager.ApplicationParts.Add(new AssemblyPart(assembly));
|
||||
applicationPartManager.FeatureProviders.Add(new MetadataReferenceFeatureProvider());
|
||||
|
||||
return applicationPartManager;
|
||||
}
|
||||
|
||||
private static IOptions<RazorViewEngineOptions> GetAccessor(RazorViewEngineOptions options)
|
||||
{
|
||||
var optionsAccessor = new Mock<IOptions<RazorViewEngineOptions>>();
|
||||
optionsAccessor.SetupGet(a => a.Value).Returns(options);
|
||||
return optionsAccessor.Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +211,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
feature => Assert.IsType<ControllerFeatureProvider>(feature),
|
||||
feature => Assert.IsType<ViewComponentFeatureProvider>(feature),
|
||||
feature => Assert.IsType<TagHelperFeatureProvider>(feature),
|
||||
feature => Assert.IsType<MetadataReferenceFeatureProvider>(feature));
|
||||
feature => Assert.IsType<MetadataReferenceFeatureProvider>(feature),
|
||||
feature => Assert.IsType<ViewsFeatureProvider>(feature));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue