зеркало из https://github.com/aspnet/Mvc.git
Remove Razor precompilation
This commit is contained in:
Родитель
d0046cafe9
Коммит
32d15186a0
|
@ -99,7 +99,7 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LocalizationSample.Web", "s
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ActionConstraintSample.Web", "samples\ActionConstraintSample.Web\ActionConstraintSample.Web.xproj", "{EE0BD773-4D47-4AA8-8472-5A938A3953BA}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "samples\MvcSubAreaSample.Web\MvcSubAreaSample.Web.xproj", "{E1D45BAF-3967-4D81-9217-22AA54941BF5}"
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "samples\MvcSubAreaSample.Web\MvcSubAreaSample.Web.xproj", "{45F6B3B6-D114-4D77-84D6-561B3957F341}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -593,18 +593,18 @@ Global
|
|||
{EE0BD773-4D47-4AA8-8472-5A938A3953BA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{EE0BD773-4D47-4AA8-8472-5A938A3953BA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EE0BD773-4D47-4AA8-8472-5A938A3953BA}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -652,6 +652,6 @@ Global
|
|||
{DAB1252D-577C-4912-98BE-1A812BF83F86} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{FCFE6024-2720-49B4-8257-9DBC6114F0F1} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{EE0BD773-4D47-4AA8-8472-5A938A3953BA} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{E1D45BAF-3967-4D81-9217-22AA54941BF5} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{45F6B3B6-D114-4D77-84D6-561B3957F341} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
13
Mvc.sln
13
Mvc.sln
|
@ -70,8 +70,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHel
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers.Test", "test\Microsoft.AspNet.Mvc.TagHelpers.Test\Microsoft.AspNet.Mvc.TagHelpers.Test.xproj", "{860119ED-3DB1-424D-8D0A-30132A8A7D96}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PrecompilationWebSite", "test\WebSites\PrecompilationWebSite\PrecompilationWebSite.xproj", "{59E1BE90-92C1-4D35-ADCC-B69F49077C81}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HtmlGenerationWebSite", "test\WebSites\HtmlGenerationWebSite\HtmlGenerationWebSite.xproj", "{920F8A0E-6F7D-4BBE-84FF-840B89099BE6}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ErrorPageMiddlewareWebSite", "test\WebSites\ErrorPageMiddlewareWebSite\ErrorPageMiddlewareWebSite.xproj", "{AD545A5B-2BA5-4314-88AC-FC2ACF2CC718}"
|
||||
|
@ -426,16 +424,6 @@ Global
|
|||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{920F8A0E-6F7D-4BBE-84FF-840B89099BE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{920F8A0E-6F7D-4BBE-84FF-840B89099BE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{920F8A0E-6F7D-4BBE-84FF-840B89099BE6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
@ -912,7 +900,6 @@ Global
|
|||
{2223120F-D675-40DA-8CD8-11DC14A0B2C7} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{B2347320-308E-4D2B-AEC8-005DFA68B0C9} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{59E1BE90-92C1-4D35-ADCC-B69F49077C81} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{920F8A0E-6F7D-4BBE-84FF-840B89099BE6} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{AD545A5B-2BA5-4314-88AC-FC2ACF2CC718} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{C3123A70-41C4-4122-AD1C-D35DF8958DD7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="14.0.24720" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.24720</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>59e1be90-92c1-4d35-adcc-b69f49077c81</ProjectGuid>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
<ProjectGuid>45F6B3B6-D114-4D77-84D6-561B3957F341</ProjectGuid>
|
||||
<RootNamespace>MvcSubAreaSample.Web</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>40958</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -1,12 +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 Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
|
||||
namespace TagHelperSample.Web
|
||||
{
|
||||
public class TagHelpersRazorPreCompilation : RazorPreCompileModule
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,109 +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.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ICompilerCacheProvider"/> that provides a <see cref="CompilerCache"/> instance
|
||||
/// populated with precompiled views.
|
||||
/// </summary>
|
||||
public class PrecompiledViewsCompilerCacheProvider : ICompilerCacheProvider
|
||||
{
|
||||
private static readonly Assembly RazorAssembly = typeof(DefaultCompilerCacheProvider).GetTypeInfo().Assembly;
|
||||
private static readonly Type RazorFileInfoCollectionType = typeof(RazorFileInfoCollection);
|
||||
private readonly Func<ICompilerCache> _createCache;
|
||||
private readonly IAssemblyLoadContextAccessor _loadContextAccessor;
|
||||
private readonly IFileProvider _fileProvider;
|
||||
private readonly Assembly[] _assemblies;
|
||||
|
||||
private object _cacheLock = new object();
|
||||
private bool _cacheInitialized;
|
||||
private ICompilerCache _compilerCache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="loadContextAccessor">The <see cref="IAssemblyLoadContextAccessor"/>.</param>
|
||||
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
|
||||
/// <param name="assemblies"><see cref="Assembly"/> instances to scan for precompiled views.</param>
|
||||
public PrecompiledViewsCompilerCacheProvider(
|
||||
IAssemblyLoadContextAccessor loadContextAccessor,
|
||||
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
|
||||
IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
_loadContextAccessor = loadContextAccessor;
|
||||
_fileProvider = fileProviderAccessor.FileProvider;
|
||||
_createCache = CreateCache;
|
||||
_assemblies = assemblies.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICompilerCache Cache
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _compilerCache,
|
||||
ref _cacheInitialized,
|
||||
ref _cacheLock,
|
||||
_createCache);
|
||||
}
|
||||
}
|
||||
|
||||
private ICompilerCache CreateCache()
|
||||
{
|
||||
var razorFileInfoCollections = GetFileInfoCollections(_assemblies);
|
||||
var loadContext = _loadContextAccessor.GetLoadContext(RazorAssembly);
|
||||
var precompiledViews = GetPrecompiledViews(razorFileInfoCollections, loadContext);
|
||||
|
||||
return new CompilerCache(_fileProvider, precompiledViews);
|
||||
}
|
||||
|
||||
// Internal for unit testing
|
||||
internal static Dictionary<string, Type> GetPrecompiledViews(
|
||||
IEnumerable<RazorFileInfoCollection> razorFileInfoCollections,
|
||||
IAssemblyLoadContext loadContext)
|
||||
{
|
||||
var precompiledViews = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var viewCollection in razorFileInfoCollections)
|
||||
{
|
||||
var containingAssembly = viewCollection.LoadAssembly(loadContext);
|
||||
foreach (var fileInfo in viewCollection.FileInfos)
|
||||
{
|
||||
var viewType = containingAssembly.GetType(fileInfo.FullTypeName);
|
||||
precompiledViews[fileInfo.RelativePath] = viewType;
|
||||
}
|
||||
}
|
||||
|
||||
return precompiledViews;
|
||||
}
|
||||
|
||||
private static IEnumerable<RazorFileInfoCollection> GetFileInfoCollections(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return assemblies
|
||||
.SelectMany(assembly => assembly.ExportedTypes)
|
||||
.Where(IsValidRazorFileInfoCollection)
|
||||
.Select(Activator.CreateInstance)
|
||||
.Cast<RazorFileInfoCollection>();
|
||||
}
|
||||
|
||||
internal static bool IsValidRazorFileInfoCollection(Type type)
|
||||
{
|
||||
return
|
||||
RazorFileInfoCollectionType.IsAssignableFrom(type) &&
|
||||
!type.GetTypeInfo().IsAbstract &&
|
||||
!type.GetTypeInfo().ContainsGenericParameters;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,28 +73,5 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IMvcBuilder AddPrecompiledRazorViews(
|
||||
this IMvcBuilder builder,
|
||||
params Assembly[] assemblies)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (assemblies == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assemblies));
|
||||
}
|
||||
|
||||
builder.Services.Replace(
|
||||
ServiceDescriptor.Singleton<ICompilerCacheProvider>(serviceProvider =>
|
||||
ActivatorUtilities.CreateInstance<PrecompiledViewsCompilerCacheProvider>(
|
||||
serviceProvider,
|
||||
assemblies.AsEnumerable())));
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,31 +58,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
public static IMvcCoreBuilder AddPrecompiledRazorViews(
|
||||
this IMvcCoreBuilder builder,
|
||||
params Assembly[] assemblies)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (assemblies == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assemblies));
|
||||
}
|
||||
|
||||
AddRazorViewEngine(builder);
|
||||
|
||||
builder.Services.Replace(
|
||||
ServiceDescriptor.Singleton<ICompilerCacheProvider>(serviceProvider =>
|
||||
ActivatorUtilities.CreateInstance<PrecompiledViewsCompilerCacheProvider>(
|
||||
serviceProvider,
|
||||
assemblies.AsEnumerable())));
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an initialization callback for a given <typeparamref name="TTagHelper"/>.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,76 +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.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility type to code generate <see cref="RazorFileInfoCollection"/> types.
|
||||
/// </summary>
|
||||
public static class RazorFileInfoCollectionGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates CSharp code for the specified <paramref name="fileInfoCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="fileInfoCollection">The <see cref="RazorFileInfoCollection"/>.</param>
|
||||
/// <returns></returns>
|
||||
public static string GenerateCode(RazorFileInfoCollection fileInfoCollection)
|
||||
{
|
||||
if (fileInfoCollection == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fileInfoCollection));
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append(
|
||||
$@"namespace __ASP_ASSEMBLY
|
||||
{{
|
||||
[{typeof(CompilerGeneratedAttribute).FullName}]
|
||||
public class __PreGeneratedViewCollection : {typeof(RazorFileInfoCollection).FullName}
|
||||
{{
|
||||
public __PreGeneratedViewCollection()
|
||||
{{
|
||||
{nameof(RazorFileInfoCollection.AssemblyResourceName)} = @""{fileInfoCollection.AssemblyResourceName}"";
|
||||
{nameof(RazorFileInfoCollection.SymbolsResourceName)} = @""{fileInfoCollection.SymbolsResourceName}"";
|
||||
FileInfos = new System.Collections.Generic.List<{typeof(RazorFileInfo).FullName}>
|
||||
{{");
|
||||
|
||||
foreach (var fileInfo in fileInfoCollection.FileInfos)
|
||||
{
|
||||
builder.Append(
|
||||
$@"
|
||||
new {typeof(RazorFileInfo).FullName}
|
||||
{{
|
||||
{nameof(RazorFileInfo.FullTypeName)} = @""{fileInfo.FullTypeName}"",
|
||||
{nameof(RazorFileInfo.RelativePath)} = @""{fileInfo.RelativePath}""
|
||||
}},");
|
||||
}
|
||||
|
||||
builder.Append(
|
||||
$@"
|
||||
}};
|
||||
}}
|
||||
|
||||
private static {typeof(System.Reflection.Assembly).FullName} _loadedAssembly;
|
||||
|
||||
public override {typeof(System.Reflection.Assembly).FullName} LoadAssembly(
|
||||
{typeof(IAssemblyLoadContext).FullName} loadContext)
|
||||
{{
|
||||
if (_loadedAssembly == null)
|
||||
{{
|
||||
_loadedAssembly = base.LoadAssembly(loadContext);
|
||||
}}
|
||||
return _loadedAssembly;
|
||||
}}
|
||||
}}
|
||||
}}");
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +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.Linq;
|
||||
using Microsoft.AspNet.Razor.CodeGenerators;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
public static class GeneratorResultExtensions
|
||||
{
|
||||
public static string GetMainClassName(
|
||||
this GeneratorResults results,
|
||||
IMvcRazorHost host,
|
||||
SyntaxTree syntaxTree)
|
||||
{
|
||||
if (results == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(results));
|
||||
}
|
||||
|
||||
if (host == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(host));
|
||||
}
|
||||
|
||||
if (syntaxTree == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(syntaxTree));
|
||||
}
|
||||
|
||||
// The mainClass name should return directly from the generator results.
|
||||
var classes = syntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>();
|
||||
var mainClass = classes.FirstOrDefault(c =>
|
||||
c.Identifier.ValueText.StartsWith(host.MainClassNamePrefix, StringComparison.Ordinal));
|
||||
|
||||
if (mainClass != null)
|
||||
{
|
||||
var typeName = mainClass.Identifier.ValueText;
|
||||
|
||||
if (!string.IsNullOrEmpty(host.DefaultNamespace))
|
||||
{
|
||||
typeName = host.DefaultNamespace + "." + typeName;
|
||||
}
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
/// <summary>
|
||||
/// An entry in the cache used by <see cref="RazorPreCompiler"/>.
|
||||
/// </summary>
|
||||
public class PrecompilationCacheEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="PrecompilationCacheEntry"/> for a successful parse.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The <see cref="RazorFileInfo"/> of the file being cached.</param>
|
||||
/// <param name="syntaxTree">The <see cref="CodeAnalysis.SyntaxTree"/> to cache.</param>
|
||||
public PrecompilationCacheEntry(
|
||||
RazorFileInfo fileInfo,
|
||||
SyntaxTree syntaxTree)
|
||||
{
|
||||
if (fileInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fileInfo));
|
||||
}
|
||||
|
||||
if (syntaxTree == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(syntaxTree));
|
||||
}
|
||||
|
||||
FileInfo = fileInfo;
|
||||
SyntaxTree = syntaxTree;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="PrecompilationCacheEntry"/> for a failed parse.
|
||||
/// </summary>
|
||||
/// <param name="diagnostics">The <see cref="IReadOnlyList{Diagnostic}"/> produced from parsing the Razor
|
||||
/// file. This does not contain <see cref="Diagnostic"/>s produced from compiling the parsed
|
||||
/// <see cref="CodeAnalysis.SyntaxTree"/>.</param>
|
||||
public PrecompilationCacheEntry(IReadOnlyList<Diagnostic> diagnostics)
|
||||
{
|
||||
if (diagnostics == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(diagnostics));
|
||||
}
|
||||
|
||||
Diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="RazorFileInfo"/> associated with this cache entry instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is not <c>null</c> if <see cref="Success"/> is <c>true</c>.
|
||||
/// </remarks>
|
||||
public RazorFileInfo FileInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="SyntaxTree"/> produced from parsing the Razor file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is not <c>null</c> if <see cref="Success"/> is <c>true</c>.
|
||||
/// </remarks>
|
||||
public SyntaxTree SyntaxTree { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Diagnostic"/>s produced from parsing the generated contents of the file
|
||||
/// specified by <see cref="FileInfo"/>. This does not contain <see cref="Diagnostic"/>s produced from
|
||||
/// compiling the parsed <see cref="CodeAnalysis.SyntaxTree"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is <c>null</c> if <see cref="Success"/> is <c>true</c>.
|
||||
/// </remarks>
|
||||
public IReadOnlyList<Diagnostic> Diagnostics { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates if parsing was successful.
|
||||
/// </summary>
|
||||
public bool Success
|
||||
{
|
||||
get { return SyntaxTree != null; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +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 Microsoft.AspNet.Razor;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
public static class RazorErrorExtensions
|
||||
{
|
||||
public static Diagnostic ToDiagnostics(this RazorError error, string filePath)
|
||||
{
|
||||
if (error == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(error));
|
||||
}
|
||||
|
||||
if (filePath == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filePath));
|
||||
}
|
||||
|
||||
var descriptor = new DiagnosticDescriptor(
|
||||
id: "Razor",
|
||||
title: "Razor parsing error",
|
||||
messageFormat: error.Message.Replace("{", "{{").Replace("}", "}}"),
|
||||
category: "Razor.Parser",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true);
|
||||
|
||||
var location = error.Location;
|
||||
if (location.Equals(SourceLocation.Undefined))
|
||||
{
|
||||
location = SourceLocation.Zero;
|
||||
}
|
||||
var length = Math.Max(0, error.Length);
|
||||
|
||||
var textSpan = new TextSpan(location.AbsoluteIndex, length);
|
||||
var linePositionStart = new LinePosition(location.LineIndex, location.CharacterIndex);
|
||||
var linePositionEnd = new LinePosition(location.LineIndex, location.CharacterIndex + length);
|
||||
var linePositionSpan = new LinePositionSpan(linePositionStart, linePositionEnd);
|
||||
return Diagnostic.Create(descriptor, Location.Create(filePath, textSpan, linePositionSpan));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +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.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
/// <summary>
|
||||
/// Metadata for precompiled files.
|
||||
/// </summary>
|
||||
public class RazorFileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Type name including namespace.
|
||||
/// </summary>
|
||||
public string FullTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to to the file relative to the application base.
|
||||
/// </summary>
|
||||
public string RelativePath { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,63 +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.Reflection;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies metadata about precompiled views.
|
||||
/// </summary>
|
||||
public abstract class RazorFileInfoCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the resource containing the precompiled binary.
|
||||
/// </summary>
|
||||
public string AssemblyResourceName { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the resource that contains the symbols (pdb).
|
||||
/// </summary>
|
||||
public string SymbolsResourceName { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IReadOnlyList{T}"/> of <see cref="RazorFileInfo"/>s.
|
||||
/// </summary>
|
||||
public IReadOnlyList<RazorFileInfo> FileInfos { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Loads the assembly containing precompiled views.
|
||||
/// </summary>
|
||||
/// <param name="loadContext">The <see cref="IAssemblyLoadContext"/>.</param>
|
||||
/// <returns>The <see cref="Assembly"/> containing precompiled views.</returns>
|
||||
public virtual Assembly LoadAssembly(IAssemblyLoadContext loadContext)
|
||||
{
|
||||
var viewCollectionAssembly = GetType().GetTypeInfo().Assembly;
|
||||
|
||||
using (var assemblyStream = viewCollectionAssembly.GetManifestResourceStream(AssemblyResourceName))
|
||||
{
|
||||
if (assemblyStream == null)
|
||||
{
|
||||
var message = Resources.FormatRazorFileInfoCollection_ResourceCouldNotBeFound(AssemblyResourceName,
|
||||
GetType().FullName);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
Stream symbolsStream = null;
|
||||
if (!string.IsNullOrEmpty(SymbolsResourceName))
|
||||
{
|
||||
symbolsStream = viewCollectionAssembly.GetManifestResourceStream(SymbolsResourceName);
|
||||
}
|
||||
|
||||
using (symbolsStream)
|
||||
{
|
||||
return loadContext.LoadStream(assemblyStream, symbolsStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,121 +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.Runtime.Versioning;
|
||||
using Microsoft.AspNet.FileProviders;
|
||||
using Microsoft.Dnx.Compilation.CSharp;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ICompileModule"/> implementation that pre-compiles Razor views in the application.
|
||||
/// </summary>
|
||||
public abstract class RazorPreCompileModule : ICompileModule
|
||||
{
|
||||
private const string ReleaseConfiguration = "release";
|
||||
private readonly object _memoryCacheLookupLock = new object();
|
||||
private readonly Dictionary<PrecompilationCacheKey, MemoryCache> _memoryCacheLookup =
|
||||
new Dictionary<PrecompilationCacheKey, MemoryCache>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines if symbols (.pdb) file for the precompiled views is generated.
|
||||
/// </summary>
|
||||
public bool GenerateSymbols { get; protected set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>Pre-compiles all Razor views in the application.</remarks>
|
||||
public virtual void BeforeCompile(BeforeCompileContext context)
|
||||
{
|
||||
if (!EnablePreCompilation(context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryCache memoryCache;
|
||||
lock (_memoryCacheLookupLock)
|
||||
{
|
||||
var cacheKey = new PrecompilationCacheKey
|
||||
{
|
||||
Configuration = context.ProjectContext.Configuration,
|
||||
TargetFramework = context.ProjectContext.TargetFramework
|
||||
};
|
||||
|
||||
if (!_memoryCacheLookup.TryGetValue(cacheKey, out memoryCache))
|
||||
{
|
||||
// When CompactOnMemoryPressure is true, the MemoryCache evicts items at every gen2 collection.
|
||||
// In DTH, gen2 happens frequently enough to make it undesirable for caching precompilation results. We'll
|
||||
// disable listening for memory pressure for the MemoryCache instance used by precompilation.
|
||||
memoryCache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false });
|
||||
|
||||
_memoryCacheLookup[cacheKey] = memoryCache;
|
||||
}
|
||||
}
|
||||
|
||||
using (var fileProvider = new PhysicalFileProvider(context.ProjectContext.ProjectDirectory))
|
||||
{
|
||||
var viewCompiler = new RazorPreCompiler(
|
||||
context,
|
||||
fileProvider,
|
||||
memoryCache)
|
||||
{
|
||||
GenerateSymbols = GenerateSymbols
|
||||
};
|
||||
|
||||
viewCompiler.CompileViews();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AfterCompile(AfterCompileContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this instance of <see cref="RazorPreCompileModule"/> should enable
|
||||
/// compilation of views.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="BeforeCompileContext"/>.</param>
|
||||
/// <returns><c>true</c> if views should be precompiled; otherwise <c>false</c>.</returns>
|
||||
/// <remarks>Returns <c>true</c> if the current application is being built in <c>release</c>
|
||||
/// configuration.</remarks>
|
||||
protected virtual bool EnablePreCompilation(BeforeCompileContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
return string.Equals(
|
||||
context.ProjectContext.Configuration,
|
||||
ReleaseConfiguration,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private class PrecompilationCacheKey : IEquatable<PrecompilationCacheKey>
|
||||
{
|
||||
public string Configuration { get; set; }
|
||||
|
||||
public FrameworkName TargetFramework { get; set; }
|
||||
|
||||
public bool Equals(PrecompilationCacheKey other)
|
||||
{
|
||||
return
|
||||
other.TargetFramework == TargetFramework &&
|
||||
string.Equals(other.Configuration, Configuration, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
||||
hashCodeCombiner.Add(Configuration);
|
||||
hashCodeCombiner.Add(TargetFramework);
|
||||
|
||||
return hashCodeCombiner;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,356 +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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
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.CSharp;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.CompilationAbstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
public class RazorPreCompiler
|
||||
{
|
||||
private const string CacheKeyDirectorySeparator = "/";
|
||||
private readonly TagHelperDescriptorFactory _tagHelperDescriptorFactory =
|
||||
new TagHelperDescriptorFactory(designTime: false);
|
||||
|
||||
public RazorPreCompiler(
|
||||
BeforeCompileContext compileContext,
|
||||
IFileProvider fileProvider,
|
||||
IMemoryCache precompilationCache)
|
||||
{
|
||||
if (compileContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(compileContext));
|
||||
}
|
||||
|
||||
if (fileProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fileProvider));
|
||||
}
|
||||
|
||||
if (precompilationCache == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(precompilationCache));
|
||||
}
|
||||
|
||||
CompileContext = compileContext;
|
||||
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,
|
||||
Defines = defines,
|
||||
LanguageVersion = compileContext.Compilation.LanguageVersion
|
||||
};
|
||||
PreCompilationCache = precompilationCache;
|
||||
TagHelperTypeResolver = new PrecompilationTagHelperTypeResolver(CompileContext.Compilation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines if symbols (.pdb) file for the precompiled views is generated.
|
||||
/// </summary>
|
||||
public bool GenerateSymbols { get; set; }
|
||||
|
||||
protected IFileProvider FileProvider { get; }
|
||||
|
||||
protected BeforeCompileContext CompileContext { get; }
|
||||
|
||||
protected CompilationSettings CompilationSettings { get; }
|
||||
|
||||
protected IMemoryCache PreCompilationCache { get; }
|
||||
|
||||
protected virtual string FileExtension { get; } = ".cshtml";
|
||||
|
||||
protected virtual int MaxDegreesOfParallelism { get; } = Environment.ProcessorCount;
|
||||
|
||||
protected virtual TagHelperTypeResolver TagHelperTypeResolver { get; }
|
||||
|
||||
public virtual void CompileViews()
|
||||
{
|
||||
var result = CreateFileInfoCollection();
|
||||
if (result != null)
|
||||
{
|
||||
var generatedCode = RazorFileInfoCollectionGenerator.GenerateCode(result);
|
||||
var syntaxTree = CSharpSyntaxTree.ParseText(
|
||||
generatedCode,
|
||||
SyntaxTreeGenerator.GetParseOptions(CompilationSettings));
|
||||
CompileContext.Compilation = CompileContext.Compilation.AddSyntaxTrees(syntaxTree);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual RazorFileInfoCollection CreateFileInfoCollection()
|
||||
{
|
||||
var filesToProcess = new List<RelativeFileInfo>();
|
||||
GetFileInfosRecursive(root: string.Empty, razorFiles: filesToProcess);
|
||||
if (filesToProcess.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var razorFiles = new RazorFileInfo[filesToProcess.Count];
|
||||
var syntaxTrees = new SyntaxTree[filesToProcess.Count];
|
||||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = MaxDegreesOfParallelism };
|
||||
var diagnosticsLock = new object();
|
||||
var hasErrors = false;
|
||||
|
||||
Parallel.For(0, filesToProcess.Count, parallelOptions, index =>
|
||||
{
|
||||
var file = filesToProcess[index];
|
||||
|
||||
PrecompilationCacheEntry cacheEntry;
|
||||
if (!PreCompilationCache.TryGetValue(file.RelativePath, out cacheEntry))
|
||||
{
|
||||
cacheEntry = GetCacheEntry(file);
|
||||
PreCompilationCache.Set(
|
||||
file.RelativePath,
|
||||
cacheEntry,
|
||||
GetMemoryCacheEntryOptions(file, cacheEntry));
|
||||
}
|
||||
|
||||
if (cacheEntry != null)
|
||||
{
|
||||
if (cacheEntry.Success)
|
||||
{
|
||||
syntaxTrees[index] = cacheEntry.SyntaxTree;
|
||||
razorFiles[index] = cacheEntry.FileInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasErrors = true;
|
||||
lock (diagnosticsLock)
|
||||
{
|
||||
AddRange(CompileContext.Diagnostics, cacheEntry.Diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasErrors)
|
||||
{
|
||||
// If any of the Razor files had syntax errors, don't emit the precompiled views assembly.
|
||||
return null;
|
||||
}
|
||||
|
||||
return GeneratePrecompiledAssembly(
|
||||
syntaxTrees.Where(tree => tree != null),
|
||||
razorFiles.Where(file => file != null));
|
||||
}
|
||||
|
||||
protected virtual RazorFileInfoCollection GeneratePrecompiledAssembly(
|
||||
IEnumerable<SyntaxTree> syntaxTrees,
|
||||
IEnumerable<RazorFileInfo> razorFileInfos)
|
||||
{
|
||||
if (syntaxTrees == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(syntaxTrees));
|
||||
}
|
||||
|
||||
if (razorFileInfos == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(razorFileInfos));
|
||||
}
|
||||
|
||||
var resourcePrefix = string.Join(".", CompileContext.Compilation.AssemblyName,
|
||||
nameof(RazorPreCompiler),
|
||||
Path.GetRandomFileName());
|
||||
var assemblyResourceName = resourcePrefix + ".dll";
|
||||
|
||||
|
||||
var applicationReference = CompileContext.Compilation.ToMetadataReference();
|
||||
var references = CompileContext.Compilation.References
|
||||
.Concat(new[] { applicationReference });
|
||||
|
||||
var preCompilationOptions = CompilationSettings
|
||||
.CompilationOptions
|
||||
.WithOutputKind(OutputKind.DynamicallyLinkedLibrary);
|
||||
|
||||
var compilation = CSharpCompilation.Create(
|
||||
assemblyResourceName,
|
||||
options: preCompilationOptions,
|
||||
syntaxTrees: syntaxTrees,
|
||||
references: references);
|
||||
|
||||
var generateSymbols = GenerateSymbols && SymbolsUtility.SupportsSymbolsGeneration();
|
||||
// These streams are returned to the runtime and consequently cannot be disposed.
|
||||
var assemblyStream = new MemoryStream();
|
||||
var pdbStream = generateSymbols ? new MemoryStream() : null;
|
||||
var emitResult = compilation.Emit(assemblyStream, pdbStream);
|
||||
if (!emitResult.Success)
|
||||
{
|
||||
AddRange(CompileContext.Diagnostics, emitResult.Diagnostics);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var assemblyResource = new ResourceDescriptor()
|
||||
{
|
||||
FileName = Path.GetFileName(assemblyResourceName),
|
||||
Name = assemblyResourceName,
|
||||
StreamFactory = () => GetNonDisposableStream(assemblyStream)
|
||||
};
|
||||
CompileContext.Resources.Add(assemblyResource);
|
||||
|
||||
string symbolsResourceName = null;
|
||||
if (pdbStream != null)
|
||||
{
|
||||
symbolsResourceName = resourcePrefix + ".pdb";
|
||||
var pdbResource = new ResourceDescriptor()
|
||||
{
|
||||
FileName = Path.GetFileName(symbolsResourceName),
|
||||
Name = symbolsResourceName,
|
||||
StreamFactory = () => GetNonDisposableStream(pdbStream)
|
||||
};
|
||||
|
||||
CompileContext.Resources.Add(pdbResource);
|
||||
}
|
||||
|
||||
return new PrecompileRazorFileInfoCollection(assemblyResourceName,
|
||||
symbolsResourceName,
|
||||
razorFileInfos.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
protected IMvcRazorHost GetRazorHost()
|
||||
{
|
||||
var descriptorResolver = new TagHelperDescriptorResolver(
|
||||
TagHelperTypeResolver,
|
||||
_tagHelperDescriptorFactory);
|
||||
return new MvcRazorHost(new DefaultChunkTreeCache(FileProvider))
|
||||
{
|
||||
TagHelperDescriptorResolver = descriptorResolver
|
||||
};
|
||||
}
|
||||
|
||||
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions(
|
||||
RelativeFileInfo fileInfo,
|
||||
PrecompilationCacheEntry cacheEntry)
|
||||
{
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
options.AddExpirationToken(FileProvider.Watch(fileInfo.RelativePath));
|
||||
foreach (var path in ViewHierarchyUtility.GetViewImportsLocations(fileInfo.RelativePath))
|
||||
{
|
||||
options.AddExpirationToken(FileProvider.Watch(path));
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
private void GetFileInfosRecursive(string root, List<RelativeFileInfo> razorFiles)
|
||||
{
|
||||
var fileInfos = FileProvider.GetDirectoryContents(root);
|
||||
|
||||
foreach (var fileInfo in fileInfos)
|
||||
{
|
||||
if (fileInfo.IsDirectory)
|
||||
{
|
||||
var subPath = CombinePath(root, fileInfo.Name);
|
||||
GetFileInfosRecursive(subPath, razorFiles);
|
||||
}
|
||||
else if (Path.GetExtension(fileInfo.Name)
|
||||
.Equals(FileExtension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var relativePath = CombinePath(root, fileInfo.Name);
|
||||
var info = new RelativeFileInfo(fileInfo, relativePath);
|
||||
razorFiles.Add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual PrecompilationCacheEntry GetCacheEntry(RelativeFileInfo fileInfo)
|
||||
{
|
||||
if (fileInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fileInfo));
|
||||
}
|
||||
|
||||
using (var stream = fileInfo.FileInfo.CreateReadStream())
|
||||
{
|
||||
using (var host = GetRazorHost())
|
||||
{
|
||||
var results = host.GenerateCode(fileInfo.RelativePath, stream);
|
||||
|
||||
if (results.Success)
|
||||
{
|
||||
var syntaxTree = SyntaxTreeGenerator.Generate(
|
||||
results.GeneratedCode,
|
||||
fileInfo.FileInfo.PhysicalPath,
|
||||
CompilationSettings);
|
||||
var fullTypeName = results.GetMainClassName(host, syntaxTree);
|
||||
|
||||
if (fullTypeName != null)
|
||||
{
|
||||
var razorFileInfo = new RazorFileInfo
|
||||
{
|
||||
RelativePath = fileInfo.RelativePath,
|
||||
FullTypeName = fullTypeName
|
||||
};
|
||||
|
||||
return new PrecompilationCacheEntry(razorFileInfo, syntaxTree);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var diagnostics = results
|
||||
.ParserErrors
|
||||
.Select(error => error.ToDiagnostics(fileInfo.FileInfo.PhysicalPath))
|
||||
.ToList();
|
||||
|
||||
return new PrecompilationCacheEntry(diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void AddRange<TVal>(IList<TVal> target, IEnumerable<TVal> source)
|
||||
{
|
||||
foreach (var diagnostic in source)
|
||||
{
|
||||
target.Add(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream GetNonDisposableStream(Stream stream)
|
||||
{
|
||||
stream.Position = 0;
|
||||
return new NonDisposableStream(stream);
|
||||
}
|
||||
|
||||
private static string CombinePath(string root, string name)
|
||||
{
|
||||
// We use string.Join instead of Path.Combine here to ensure that the path
|
||||
// separator we produce matches the one used by the CompilerCache.
|
||||
return string.Join(CacheKeyDirectorySeparator, root, name);
|
||||
}
|
||||
|
||||
private class PrecompileRazorFileInfoCollection : RazorFileInfoCollection
|
||||
{
|
||||
public PrecompileRazorFileInfoCollection(
|
||||
string assemblyResourceName,
|
||||
string symbolsResourceName,
|
||||
IReadOnlyList<RazorFileInfo> fileInfos)
|
||||
{
|
||||
AssemblyResourceName = assemblyResourceName;
|
||||
SymbolsResourceName = symbolsResourceName;
|
||||
FileInfos = fileInfos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@
|
|||
"Microsoft.AspNet.FileProviders.Composite": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*",
|
||||
"Microsoft.AspNet.Razor.Runtime.Precompilation": "4.0.0-*",
|
||||
"Microsoft.Extensions.HashCodeCombiner.Sources": {
|
||||
"version": "1.0.0-*",
|
||||
"type": "build"
|
||||
|
|
|
@ -1,137 +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.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
using Microsoft.AspNet.Testing.xunit;
|
||||
using PrecompilationWebSite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class PrecompilationTest : IClassFixture<MvcTestFixture<PrecompilationWebSite.Startup>>
|
||||
{
|
||||
public PrecompilationTest(MvcTestFixture<PrecompilationWebSite.Startup> fixture)
|
||||
{
|
||||
Client = fixture.Client;
|
||||
}
|
||||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[ConditionalFact]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task PrecompiledView_RendersCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
// We will render a view that writes the fully qualified name of the Assembly containing the type of
|
||||
// the view. If the view is precompiled, this assembly will be PrecompilationWebsite.
|
||||
var assemblyNamePrefix = GetAssemblyNamePrefix();
|
||||
|
||||
// Act
|
||||
var response = await Client.GetAsync("http://localhost/Home/Index");
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var parsedResponse1 = new ParsedResponse(responseContent);
|
||||
Assert.StartsWith(assemblyNamePrefix, parsedResponse1.ViewStart);
|
||||
Assert.StartsWith(assemblyNamePrefix, parsedResponse1.Layout);
|
||||
Assert.StartsWith(assemblyNamePrefix, parsedResponse1.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PrecompiledView_UsesCompilationOptionsFromApplication()
|
||||
{
|
||||
// Arrange
|
||||
var assemblyNamePrefix = GetAssemblyNamePrefix();
|
||||
#if DNX451
|
||||
var expected =
|
||||
@"Value set inside DNX451 " + assemblyNamePrefix;
|
||||
#elif DNXCORE50
|
||||
var expected =
|
||||
@"Value set inside DNXCORE50 " + assemblyNamePrefix;
|
||||
#endif
|
||||
|
||||
// Act
|
||||
var response = await Client.GetAsync("http://localhost/Home/PrecompiledViewsCanConsumeCompilationOptions");
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.StartsWith(expected, responseContent.Trim());
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task TagHelpersFromTheApplication_CanBeAdded()
|
||||
{
|
||||
// Arrange
|
||||
var assemblyNamePrefix = GetAssemblyNamePrefix();
|
||||
var expected =
|
||||
@"<root data-root=""true""><input class=""form-control"" type=""number"" data-val=""true""" +
|
||||
@" data-val-range=""The field Age must be between 10 and 100."" data-val-range-max=""100"" "+
|
||||
@"data-val-range-min=""10"" data-val-required=""The Age field is required."" " +
|
||||
@"id=""Age"" name=""Age"" value="""" /><a href=""/TagHelpers"">Back to List</a></root>";
|
||||
|
||||
// Act
|
||||
var response = await Client.GetStringAsync("http://localhost/TagHelpers/Add");
|
||||
|
||||
// Assert
|
||||
var responseLines = response.Split(new[] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
Assert.StartsWith(assemblyNamePrefix, responseLines[0]);
|
||||
Assert.Equal(expected, responseLines[1]);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task TagHelpersFromTheApplication_CanBeRemoved()
|
||||
{
|
||||
// Arrange
|
||||
var assemblyNamePrefix = GetAssemblyNamePrefix();
|
||||
var expected = @"<root>root-content</root>";
|
||||
|
||||
// Act
|
||||
var response = await Client.GetStringAsync("http://localhost/TagHelpers/Remove");
|
||||
|
||||
// Assert
|
||||
var responseLines = response.Split(new[] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
Assert.StartsWith(assemblyNamePrefix, responseLines[0]);
|
||||
Assert.Equal(expected, responseLines[1]);
|
||||
}
|
||||
|
||||
private static string GetAssemblyNamePrefix()
|
||||
{
|
||||
return typeof(Startup).GetTypeInfo().Assembly.GetName().Name + "." + nameof(RazorPreCompiler) + ".";
|
||||
}
|
||||
|
||||
private sealed class ParsedResponse
|
||||
{
|
||||
public ParsedResponse(string responseContent)
|
||||
{
|
||||
var results = responseContent
|
||||
.Split(new[] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => s.Trim())
|
||||
.ToArray();
|
||||
|
||||
Assert.True(results[0].StartsWith("Layout:"));
|
||||
Layout = results[0].Substring("Layout:".Length);
|
||||
|
||||
Assert.True(results[1].StartsWith("_viewstart:"));
|
||||
ViewStart = results[1].Substring("_viewstart:".Length);
|
||||
|
||||
Assert.True(results[2].StartsWith("index:"));
|
||||
Index = results[2].Substring("index:".Length);
|
||||
}
|
||||
|
||||
public string Layout { get; }
|
||||
|
||||
public string ViewStart { get; }
|
||||
|
||||
public string Index { get; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,6 @@
|
|||
"Microsoft.Extensions.Logging.Testing": "1.0.0-*",
|
||||
"MvcSandbox": "1.0.0",
|
||||
"MvcSubAreaSample.Web": "1.0.0",
|
||||
"PrecompilationWebSite": "1.0.0",
|
||||
"RazorPageExecutionInstrumentationWebSite": "1.0.0",
|
||||
"RazorWebSite": "1.0.0",
|
||||
"RoutingWebSite": "1.0.0",
|
||||
|
|
|
@ -1,142 +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.Reflection;
|
||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||
{
|
||||
public class PrecompiledViewsCompilerCacheProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeIsAbstract()
|
||||
{
|
||||
// Arrange
|
||||
var type = typeof(AbstractRazorFileInfoCollection);
|
||||
|
||||
// Act
|
||||
var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeHasGenericParameters()
|
||||
{
|
||||
// Arrange
|
||||
var type = typeof(GenericRazorFileInfoCollection<>);
|
||||
|
||||
// Act
|
||||
var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeDoesNotDeriveFromRazorFileInfoCollection()
|
||||
{
|
||||
// Arrange
|
||||
var type = typeof(NonSubTypeRazorFileInfoCollection);
|
||||
|
||||
// Act
|
||||
var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(ParameterConstructorRazorFileInfoCollection))]
|
||||
[InlineData(typeof(ViewCollection))]
|
||||
public void IsValidRazorFileInfoCollection_ReturnsTrue_IfTypeDerivesFromRazorFileInfoCollection(Type type)
|
||||
{
|
||||
// Act
|
||||
var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPrecompiledViews_ReturnsTypesSpecifiedByRazorFileInfoCollections()
|
||||
{
|
||||
// Arrange
|
||||
var fileInfoCollections = new[] { new ViewCollection() };
|
||||
|
||||
// Act
|
||||
var precompiledViews = PrecompiledViewsCompilerCacheProvider.GetPrecompiledViews(
|
||||
fileInfoCollections,
|
||||
Mock.Of<IAssemblyLoadContext>());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, precompiledViews.Count);
|
||||
|
||||
Type type;
|
||||
Assert.True(precompiledViews.TryGetValue("Views/Home/Index.cshtml", out type));
|
||||
Assert.Equal(typeof(TestView1), type);
|
||||
|
||||
Assert.True(precompiledViews.TryGetValue("Views/Home/About.cshtml", out type));
|
||||
Assert.Equal(typeof(TestView2), type);
|
||||
}
|
||||
|
||||
|
||||
private abstract class AbstractRazorFileInfoCollection : RazorFileInfoCollection
|
||||
{
|
||||
}
|
||||
|
||||
private class GenericRazorFileInfoCollection<TVal> : RazorFileInfoCollection
|
||||
{
|
||||
}
|
||||
|
||||
private class ParameterConstructorRazorFileInfoCollection : RazorFileInfoCollection
|
||||
{
|
||||
public ParameterConstructorRazorFileInfoCollection(string value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class NonSubTypeRazorFileInfoCollection : Controller
|
||||
{
|
||||
}
|
||||
|
||||
private class ViewCollection : RazorFileInfoCollection
|
||||
{
|
||||
public ViewCollection()
|
||||
{
|
||||
FileInfos = new[]
|
||||
{
|
||||
new RazorFileInfo
|
||||
{
|
||||
FullTypeName = typeof(TestView1).FullName,
|
||||
RelativePath = "Views/Home/Index.cshtml"
|
||||
},
|
||||
new RazorFileInfo
|
||||
{
|
||||
FullTypeName = typeof(TestView2).FullName,
|
||||
RelativePath = "Views/Home/About.cshtml"
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public override Assembly LoadAssembly(IAssemblyLoadContext loadContext)
|
||||
{
|
||||
return GetType().GetTypeInfo().Assembly;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class TestView1
|
||||
{
|
||||
}
|
||||
|
||||
private class TestView2
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,135 +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.Collections.Generic;
|
||||
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Internal
|
||||
{
|
||||
public class RazorFileInfoCollectionGeneratorTest
|
||||
{
|
||||
public static TheoryData GenerateCollection_ProducesExpectedCodeData
|
||||
{
|
||||
get
|
||||
{
|
||||
var expected1 =
|
||||
@"namespace __ASP_ASSEMBLY
|
||||
{
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute]
|
||||
public class __PreGeneratedViewCollection : Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfoCollection
|
||||
{
|
||||
public __PreGeneratedViewCollection()
|
||||
{
|
||||
AssemblyResourceName = @""EmptyAssembly"";
|
||||
SymbolsResourceName = @"""";
|
||||
FileInfos = new System.Collections.Generic.List<Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
private static System.Reflection.Assembly _loadedAssembly;
|
||||
|
||||
public override System.Reflection.Assembly LoadAssembly(
|
||||
Microsoft.Extensions.PlatformAbstractions.IAssemblyLoadContext loadContext)
|
||||
{
|
||||
if (_loadedAssembly == null)
|
||||
{
|
||||
_loadedAssembly = base.LoadAssembly(loadContext);
|
||||
}
|
||||
return _loadedAssembly;
|
||||
}
|
||||
}
|
||||
}";
|
||||
var expected2 =
|
||||
@"namespace __ASP_ASSEMBLY
|
||||
{
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute]
|
||||
public class __PreGeneratedViewCollection : Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfoCollection
|
||||
{
|
||||
public __PreGeneratedViewCollection()
|
||||
{
|
||||
AssemblyResourceName = @""TestAssembly"";
|
||||
SymbolsResourceName = @""SymbolsResource"";
|
||||
FileInfos = new System.Collections.Generic.List<Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo>
|
||||
{
|
||||
new Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo
|
||||
{
|
||||
FullTypeName = @""SomeType.Name"",
|
||||
RelativePath = @""Views/Home/Index.cshtml""
|
||||
},
|
||||
new Microsoft.AspNet.Mvc.Razor.Precompilation.RazorFileInfo
|
||||
{
|
||||
FullTypeName = @""Different.Name"",
|
||||
RelativePath = @""Views/Home/Different.cshtml""
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static System.Reflection.Assembly _loadedAssembly;
|
||||
|
||||
public override System.Reflection.Assembly LoadAssembly(
|
||||
Microsoft.Extensions.PlatformAbstractions.IAssemblyLoadContext loadContext)
|
||||
{
|
||||
if (_loadedAssembly == null)
|
||||
{
|
||||
_loadedAssembly = base.LoadAssembly(loadContext);
|
||||
}
|
||||
return _loadedAssembly;
|
||||
}
|
||||
}
|
||||
}";
|
||||
|
||||
return new TheoryData<RazorFileInfoCollection, string>
|
||||
{
|
||||
{ new EmptyCollection(), expected1 },
|
||||
{ new TestCollection(), expected2 },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateCollection_ProducesExpectedCodeData))]
|
||||
public void GenerateCollection_ProducesExpectedCode(RazorFileInfoCollection collection, string expected)
|
||||
{
|
||||
// Act
|
||||
var actual = RazorFileInfoCollectionGenerator.GenerateCode(collection);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
private class EmptyCollection : RazorFileInfoCollection
|
||||
{
|
||||
public EmptyCollection()
|
||||
{
|
||||
AssemblyResourceName = "EmptyAssembly";
|
||||
FileInfos = new List<RazorFileInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestCollection : RazorFileInfoCollection
|
||||
{
|
||||
public TestCollection()
|
||||
{
|
||||
AssemblyResourceName = "TestAssembly";
|
||||
SymbolsResourceName = "SymbolsResource";
|
||||
FileInfos = new List<RazorFileInfo>
|
||||
{
|
||||
new RazorFileInfo
|
||||
{
|
||||
FullTypeName = "SomeType.Name",
|
||||
RelativePath = @"Views/Home/Index.cshtml"
|
||||
},
|
||||
new RazorFileInfo
|
||||
{
|
||||
FullTypeName = "Different.Name",
|
||||
RelativePath = @"Views/Home/Different.cshtml"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +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 Microsoft.AspNet.Razor;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
||||
{
|
||||
public class RazorErrorExtensionsTest
|
||||
{
|
||||
public static TheoryData ToDiagnostic_SucceedsWhenRazorErrorLocationIsZeroOrUndefinedData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TheoryData<SourceLocation, int>
|
||||
{
|
||||
{ SourceLocation.Undefined, -1 },
|
||||
{ SourceLocation.Undefined, 0 },
|
||||
{ SourceLocation.Zero, -1 },
|
||||
{ SourceLocation.Zero, 0 },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ToDiagnostic_SucceedsWhenRazorErrorLocationIsZeroOrUndefinedData))]
|
||||
public void ToDiagnostic_SucceedsWhenRazorErrorLocationIsZeroOrUndefined(
|
||||
SourceLocation location,
|
||||
int length)
|
||||
{
|
||||
// Arrange
|
||||
var error = new RazorError("some message", location, length);
|
||||
|
||||
// Act
|
||||
var diagnostics = error.ToDiagnostics("/some-path");
|
||||
|
||||
// Assert
|
||||
var span = diagnostics.Location.GetMappedLineSpan();
|
||||
Assert.Equal("/some-path", span.Path);
|
||||
Assert.Equal(0, span.StartLinePosition.Line);
|
||||
Assert.Equal(0, span.StartLinePosition.Character);
|
||||
Assert.Equal(0, span.EndLinePosition.Line);
|
||||
Assert.Equal(0, span.EndLinePosition.Character);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDiagnostic_ConvertsRazorErrorLocation_ToSourceLineMappings()
|
||||
{
|
||||
// Arrange
|
||||
var sourceLocation = new SourceLocation(absoluteIndex: 30, lineIndex: 10, characterIndex: 1);
|
||||
var error = new RazorError("some message", sourceLocation, length: 5);
|
||||
|
||||
// Act
|
||||
var diagnostics = error.ToDiagnostics("/some-path");
|
||||
|
||||
// Assert
|
||||
var span = diagnostics.Location.GetMappedLineSpan();
|
||||
Assert.Equal("/some-path", span.Path);
|
||||
Assert.Equal(10, span.StartLinePosition.Line);
|
||||
Assert.Equal(1, span.StartLinePosition.Character);
|
||||
Assert.Equal(10, span.EndLinePosition.Line);
|
||||
Assert.Equal(6, span.EndLinePosition.Character);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
*.cshtml
|
|
@ -1,31 +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 Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace PrecompilationWebSite.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult PrecompiledViewsCanConsumeCompilationOptions()
|
||||
{
|
||||
return View("~/Views/ViewsConsumingCompilationOptions/Index.cshtml");
|
||||
}
|
||||
|
||||
public IActionResult GlobalDeletedPriorToFirstRequest()
|
||||
{
|
||||
return View("~/Views/ViewImportsDelete/Index.cshtml");
|
||||
}
|
||||
|
||||
[HttpGet("/Test")]
|
||||
public IActionResult TestView()
|
||||
{
|
||||
return View("~/Views/Test/Index.cshtml");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +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 Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace PrecompilationWebSite.Controllers
|
||||
{
|
||||
public class TagHelpersController : Controller
|
||||
{
|
||||
public IActionResult Add()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Remove()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +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.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PrecompilationWebSite.Models
|
||||
{
|
||||
public class Person
|
||||
{
|
||||
[Range(10, 100)]
|
||||
public int Age { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,39 +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.Reflection;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace PrecompilationWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add MVC services to the services container
|
||||
services
|
||||
.AddMvc()
|
||||
.AddPrecompiledRazorViews(GetType().GetTypeInfo().Assembly);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseCultureReplacer();
|
||||
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var application = new WebApplicationBuilder()
|
||||
.UseConfiguration(WebApplicationConfiguration.GetDefault(args))
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
application.Run();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +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 Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
||||
namespace PrecompilationWebSite.TagHelpers
|
||||
{
|
||||
[HtmlTargetElement("root")]
|
||||
public class RootViewStartTagHelper : TagHelper
|
||||
{
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes["data-root"] = "true";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
index:@GetType().GetTypeInfo().Assembly.GetName()
|
|
@ -1,2 +0,0 @@
|
|||
Layout:@GetType().GetTypeInfo().Assembly.FullName
|
||||
@RenderBody()
|
|
@ -1 +0,0 @@
|
|||
@using System.Reflection
|
|
@ -1,2 +0,0 @@
|
|||
@{ Layout = "/Views/Home/Layout.cshtml";}
|
||||
_viewstart:@GetType().GetTypeInfo().Assembly.FullName
|
|
@ -1,3 +0,0 @@
|
|||
@model PrecompilationWebSite.Models.Person
|
||||
@addTagHelper *, Microsoft.AspNet.Mvc.TagHelpers
|
||||
<root><input asp-for="Age" class="form-control" /><a asp-action="Index">Back to List</a></root>
|
|
@ -1,2 +0,0 @@
|
|||
@removeTagHelper *, PrecompilationWebSite
|
||||
<root>root-content</root>
|
|
@ -1 +0,0 @@
|
|||
@addTagHelper PrecompilationWebSite.TagHelpers.RootViewStartTagHelper, PrecompilationWebSite
|
|
@ -1,2 +0,0 @@
|
|||
@using System.Reflection
|
||||
@GetType().GetTypeInfo().Assembly.FullName
|
|
@ -1 +0,0 @@
|
|||
Test
|
|
@ -1,2 +0,0 @@
|
|||
@using System.Reflection;
|
||||
@GetType().GetTypeInfo().Assembly.FullName
|
|
@ -1 +0,0 @@
|
|||
_ViewStart content
|
|
@ -1,9 +0,0 @@
|
|||
@{
|
||||
string message =
|
||||
#if DNX451
|
||||
"Value set inside DNX451 " + GetType().Assembly.FullName;
|
||||
#elif DNXCORE50
|
||||
"Value set inside DNXCORE50 " + System.Reflection.IntrospectionExtensions.GetTypeInfo(GetType()).Assembly.FullName;
|
||||
#endif
|
||||
}
|
||||
@message
|
|
@ -1,13 +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 Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||
using Microsoft.Dnx.Compilation.CSharp;
|
||||
|
||||
namespace PrecompilationWebSite
|
||||
{
|
||||
public class RazorPreCompilation : RazorPreCompileModule
|
||||
{
|
||||
protected override bool EnablePreCompilation(BeforeCompileContext context) => true;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"server": "Microsoft.AspNet.Server.Kestrel"
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"commands": {
|
||||
"web": "PrecompilationWebSite"
|
||||
},
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
|
||||
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*",
|
||||
"Microsoft.Extensions.PropertyHelper.Sources": {
|
||||
"version": "1.0.0-*",
|
||||
"type": "build"
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": {
|
||||
"compilationOptions": {
|
||||
"define": [ "CUSTOM_DNX451_DEFINE" ]
|
||||
}
|
||||
},
|
||||
"dnxcore50": {
|
||||
"compilationOptions": {
|
||||
"define": [ "CUSTOM_DNXCORE50_DEFINE" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
PreCompilationWebSite
|
||||
===
|
||||
|
||||
This web site illustrates use cases for precompilation of razor pages.
|
|
@ -1 +0,0 @@
|
|||
HelloWorld
|
Загрузка…
Ссылка в новой задаче