Use PrecompilationTagHelperTypeResolver to locate TagHelpers during

precompilation.

Fixes #2298
This commit is contained in:
Pranav K 2015-09-09 18:25:11 -07:00
parent 894574d04e
commit 2e32ffc004
5 changed files with 9 additions and 112 deletions

View File

@ -1,88 +0,0 @@
// 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.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
{
/// <summary>
/// <see cref="TagHelperDescriptorResolver"/> used during Razor precompilation.
/// </summary>
public class PrecompilationTagHelperTypeResolver : TagHelperTypeResolver
{
private static readonly string TagHelperTypeName = typeof(ITagHelper).FullName;
private readonly BeforeCompileContext _compileContext;
private readonly IAssemblyLoadContext _loadContext;
private object _compilationLock = new object();
private bool _assemblyEmited;
private TypeInfo[] _exportedTypeInfos;
/// <summary>
/// Initializes a new instance of <see cref="PrecompilationTagHelperTypeResolver"/>.
/// </summary>
/// <param name="compileContext">The <see cref="BeforeCompileContext"/>.</param>
/// <param name="loadContext">The <see cref="IAssemblyLoadContext"/>.</param>
public PrecompilationTagHelperTypeResolver([NotNull] BeforeCompileContext compileContext,
[NotNull] IAssemblyLoadContext loadContext)
{
_compileContext = compileContext;
_loadContext = loadContext;
}
/// <inheritdoc />
protected override IEnumerable<TypeInfo> GetExportedTypes([NotNull] AssemblyName assemblyName)
{
var compilingAssemblyName = _compileContext.Compilation.AssemblyName;
if (string.Equals(assemblyName.Name, compilingAssemblyName, StringComparison.Ordinal))
{
return LazyInitializer.EnsureInitialized(ref _exportedTypeInfos,
ref _assemblyEmited,
ref _compilationLock,
GetExportedTypesFromCompilation);
}
return GetExportedTypesCore(assemblyName);
}
private IEnumerable<TypeInfo> GetExportedTypesCore(AssemblyName assemblyName)
{
var assembly = _loadContext.Load(assemblyName.Name);
return assembly.ExportedTypes.Select(type => type.GetTypeInfo());
}
private TypeInfo[] GetExportedTypesFromCompilation()
{
using (var stream = new MemoryStream())
{
var assemblyName = string.Join(".", _compileContext.Compilation.AssemblyName,
nameof(PrecompilationTagHelperTypeResolver),
Path.GetRandomFileName());
var emitResult = _compileContext.Compilation
.WithAssemblyName(assemblyName)
.Emit(stream);
if (!emitResult.Success)
{
// Return an empty sequence. Compilation will fail once precompilation completes.
return new TypeInfo[0];
}
stream.Position = 0;
var assembly = _loadContext.LoadStream(stream, assemblySymbols: null);
return assembly.ExportedTypes
.Select(type => type.GetTypeInfo())
.ToArray();
}
}
}
}

View File

@ -6,9 +6,7 @@ using System.Collections.Generic;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.FileProviders;
using Microsoft.Dnx.Compilation.CSharp; using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Razor.Precompilation namespace Microsoft.AspNet.Mvc.Razor.Precompilation
@ -18,20 +16,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
/// </summary> /// </summary>
public abstract class RazorPreCompileModule : ICompileModule public abstract class RazorPreCompileModule : ICompileModule
{ {
private readonly IAssemblyLoadContext _loadContext;
private readonly object _memoryCacheLookupLock = new object(); private readonly object _memoryCacheLookupLock = new object();
private readonly Dictionary<PrecompilationCacheKey, MemoryCache> _memoryCacheLookup = private readonly Dictionary<PrecompilationCacheKey, MemoryCache> _memoryCacheLookup =
new Dictionary<PrecompilationCacheKey, MemoryCache>(); new Dictionary<PrecompilationCacheKey, MemoryCache>();
/// <summary>
/// Instantiates a new <see cref="RazorPreCompileModule"/> instance.
/// </summary>
/// <param name="services">The <see cref="IServiceProvider"/> for the application.</param>
public RazorPreCompileModule(IServiceProvider services)
{
_loadContext = services.GetRequiredService<IAssemblyLoadContext>();
}
/// <summary> /// <summary>
/// Gets or sets a value that determines if symbols (.pdb) file for the precompiled views is generated. /// Gets or sets a value that determines if symbols (.pdb) file for the precompiled views is generated.
/// </summary> /// </summary>
@ -65,7 +53,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
var viewCompiler = new RazorPreCompiler( var viewCompiler = new RazorPreCompiler(
context, context,
_loadContext,
fileProvider, fileProvider,
memoryCache) memoryCache)
{ {

View File

@ -3,21 +3,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Razor.Compilation; using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.Directives; using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Razor.Internal; using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Razor.Runtime.Precompilation;
using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Dnx.Compilation; using Microsoft.Dnx.Compilation;
using Microsoft.Dnx.Compilation.CSharp; using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
@ -27,22 +27,22 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
{ {
public RazorPreCompiler( public RazorPreCompiler(
[NotNull] BeforeCompileContext compileContext, [NotNull] BeforeCompileContext compileContext,
[NotNull] IAssemblyLoadContext loadContext,
[NotNull] IFileProvider fileProvider, [NotNull] IFileProvider fileProvider,
[NotNull] IMemoryCache precompilationCache) [NotNull] IMemoryCache precompilationCache)
{ {
CompileContext = compileContext; CompileContext = compileContext;
LoadContext = loadContext;
FileProvider = fileProvider; FileProvider = fileProvider;
// There should always be a syntax tree even if there are no files (we generate one)
Debug.Assert(compileContext.Compilation.SyntaxTrees.Length > 0);
var defines = compileContext.Compilation.SyntaxTrees[0].Options.PreprocessorSymbolNames;
CompilationSettings = new CompilationSettings CompilationSettings = new CompilationSettings
{ {
CompilationOptions = compileContext.Compilation.Options, CompilationOptions = compileContext.Compilation.Options,
// REVIEW: There should always be a syntax tree even if there are no files (we generate one) Defines = defines,
Defines = compileContext.Compilation.SyntaxTrees[0].Options.PreprocessorSymbolNames,
LanguageVersion = compileContext.Compilation.LanguageVersion LanguageVersion = compileContext.Compilation.LanguageVersion
}; };
PreCompilationCache = precompilationCache; PreCompilationCache = precompilationCache;
TagHelperTypeResolver = new PrecompilationTagHelperTypeResolver(CompileContext, LoadContext); TagHelperTypeResolver = new PrecompilationTagHelperTypeResolver(CompileContext.Compilation);
} }
/// <summary> /// <summary>
@ -54,8 +54,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
protected BeforeCompileContext CompileContext { get; } protected BeforeCompileContext CompileContext { get; }
protected IAssemblyLoadContext LoadContext { get; }
protected CompilationSettings CompilationSettings { get; } protected CompilationSettings CompilationSettings { get; }
protected IMemoryCache PreCompilationCache { get; } protected IMemoryCache PreCompilationCache { get; }

View File

@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*", "Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*", "Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*",
"Microsoft.AspNet.Razor.Runtime.Precompilation": "4.0.0-*",
"Microsoft.AspNet.PageExecutionInstrumentation.Interfaces": "1.0.0-*", "Microsoft.AspNet.PageExecutionInstrumentation.Interfaces": "1.0.0-*",
"Microsoft.Framework.HashCodeCombiner.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.HashCodeCombiner.Sources": { "version": "1.0.0-*", "type": "build" },
"Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" },

View File

@ -8,8 +8,7 @@ namespace PrecompilationWebSite
{ {
public class RazorPreCompilation : RazorPreCompileModule public class RazorPreCompilation : RazorPreCompileModule
{ {
public RazorPreCompilation(IServiceProvider provider) public RazorPreCompilation()
: base(provider)
{ {
} }
} }