Add extensibility point to Razor compilation

This commit is contained in:
Pavel Krymets 2015-12-02 10:34:06 -08:00
parent 236ba40d00
commit 046dcefd14
5 changed files with 108 additions and 5 deletions

View File

@ -0,0 +1,33 @@
// 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.CodeAnalysis.CSharp;
namespace Microsoft.AspNet.Mvc.Razor.Compilation
{
/// <summary>
/// Context object used to pass information about the current Razor page compilation.
/// </summary>
public class RoslynCompilationContext
{
/// <summary>
/// Constructs a new instance of the <see cref="RoslynCompilationContext"/> type.
/// </summary>
/// <param name="compilation"><see cref="CSharpCompilation"/> to be set to <see cref="Compilation"/> property.</param>
public RoslynCompilationContext(CSharpCompilation compilation)
{
if (compilation == null)
{
throw new ArgumentNullException(nameof(compilation));
}
Compilation = compilation;
}
/// <summary>
/// Gets or sets the <see cref="CSharpCompilation"/> used for current source file compilation.
/// </summary>
public CSharpCompilation Compilation { get; set; }
}
}

View File

@ -40,6 +40,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
private readonly Lazy<List<MetadataReference>> _applicationReferences;
private readonly string _classPrefix;
private readonly string _configuration;
private Action<RoslynCompilationContext> _compilationCallback;
#if DOTNET5_5
private readonly RazorLoadContext _razorLoadContext;
@ -71,6 +72,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
_fileProvider = optionsAccessor.Value.FileProvider;
_classPrefix = host.MainClassNamePrefix;
_configuration = optionsAccessor.Value.Configuration;
_compilationCallback = optionsAccessor.Value.CompilationCallback;
#if DOTNET5_5
_razorLoadContext = new RazorLoadContext();
@ -111,6 +113,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
compilation = Rewrite(compilation);
var compilationContext = new RoslynCompilationContext(compilation);
_compilationCallback(compilationContext);
compilation = compilationContext.Compilation;
using (var ms = new MemoryStream())
{
using (var pdb = new MemoryStream())

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Mvc.Razor.Compilation;
namespace Microsoft.AspNet.Mvc.Razor
{
@ -16,6 +17,8 @@ namespace Microsoft.AspNet.Mvc.Razor
private string _configuration;
private Action<RoslynCompilationContext> _compilationCallback = c => { };
/// <summary>
/// Get a <see cref="IList{IViewLocationExpander}"/> used by the <see cref="RazorViewEngine"/>.
/// </summary>
@ -65,5 +68,23 @@ namespace Microsoft.AspNet.Mvc.Razor
_configuration = value;
}
}
/// <summary>
/// Gets or sets the callback that is used to customize Razor compilation
/// to change compilation settings you can update <see cref="RoslynCompilationContext.Compilation"/> property.
/// Customizations made here would not reflect in tooling (Intellisense).
/// </summary>
public Action<RoslynCompilationContext> CompilationCallback
{
get { return _compilationCallback; }
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_compilationCallback = value;
}
}
}
}

View File

@ -4,6 +4,8 @@
using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.OptionsModel;
using Microsoft.Extensions.PlatformAbstractions;
@ -19,13 +21,13 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <param name="applicationEnvironment"><see cref="IApplicationEnvironment"/> for the application.</param>
/// <param name="hostingEnvironment"><see cref="IHostingEnvironment"/> for the application.</param>
public RazorViewEngineOptionsSetup(IApplicationEnvironment applicationEnvironment, IHostingEnvironment hostingEnvironment)
public RazorViewEngineOptionsSetup(IApplicationEnvironment applicationEnvironment,
IHostingEnvironment hostingEnvironment)
: base(options => ConfigureRazor(options, applicationEnvironment, hostingEnvironment))
{
}
private static void ConfigureRazor(
RazorViewEngineOptions razorOptions,
private static void ConfigureRazor(RazorViewEngineOptions razorOptions,
IApplicationEnvironment applicationEnvironment,
IHostingEnvironment hostingEnvironment)
{

View File

@ -362,6 +362,45 @@ public class NotRazorPrefixType {}";
});
}
[Fact]
public void Compile_RunsCallback()
{
var content = "public class MyTestType {}";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
compilerOptionsProvider
.Setup(p => p.GetCompilerOptions(
applicationEnvironment.ApplicationName,
applicationEnvironment.RuntimeFramework,
ConfigurationName))
.Returns(new CompilerOptions());
RoslynCompilationContext usedCompilation = null;
var mvcRazorHost = new Mock<IMvcRazorHost>();
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
.Returns(string.Empty);
var compilationService = new RoslynCompilationService(
applicationEnvironment,
libraryExporter,
compilerOptionsProvider.Object,
mvcRazorHost.Object,
GetOptions(callback: c => usedCompilation = c));
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
Assert.NotNull(usedCompilation);
Assert.NotNull(usedCompilation.Compilation);
Assert.Equal(1, usedCompilation.Compilation.SyntaxTrees.Length);
}
private static DiagnosticDescriptor GetDiagnosticDescriptor(string messageFormat)
{
return new DiagnosticDescriptor(
@ -373,12 +412,14 @@ public class NotRazorPrefixType {}";
isEnabledByDefault: true);
}
private static IOptions<RazorViewEngineOptions> GetOptions(IFileProvider fileProvider = null)
private static IOptions<RazorViewEngineOptions> GetOptions(IFileProvider fileProvider = null,
Action<RoslynCompilationContext> callback = null)
{
var razorViewEngineOptions = new RazorViewEngineOptions
{
FileProvider = fileProvider ?? new TestFileProvider(),
Configuration = ConfigurationName
Configuration = ConfigurationName,
CompilationCallback = callback ?? (c => { })
};
var options = new Mock<IOptions<RazorViewEngineOptions>>();
options