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 Microsoft.AspNet.FileProviders;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
@ -18,20 +16,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
/// </summary>
public abstract class RazorPreCompileModule : ICompileModule
{
private readonly IAssemblyLoadContext _loadContext;
private readonly object _memoryCacheLookupLock = new object();
private readonly Dictionary<PrecompilationCacheKey, MemoryCache> _memoryCacheLookup =
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>
/// Gets or sets a value that determines if symbols (.pdb) file for the precompiled views is generated.
/// </summary>
@ -65,7 +53,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
var viewCompiler = new RazorPreCompiler(
context,
_loadContext,
fileProvider,
memoryCache)
{

View File

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

View File

@ -11,6 +11,7 @@
"dependencies": {
"Microsoft.AspNet.Mvc.Razor.Host": "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.Framework.HashCodeCombiner.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 RazorPreCompilation(IServiceProvider provider)
: base(provider)
public RazorPreCompilation()
{
}
}