-
Notifications
You must be signed in to change notification settings - Fork 9.8k
/
RazorRuntimeCompilationMvcCoreBuilderExtensions.cs
135 lines (114 loc) · 5.85 KB
/
RazorRuntimeCompilationMvcCoreBuilderExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Linq;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Routing;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Static class that adds razor runtime compilation extension methods.
/// </summary>
public static class RazorRuntimeCompilationMvcCoreBuilderExtensions
{
/// <summary>
/// Configures <see cref="IMvcCoreBuilder" /> to support runtime compilation of Razor views and Razor Pages.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder" />.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddRazorRuntimeCompilation(this IMvcCoreBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
AddServices(builder.Services);
return builder;
}
/// <summary>
/// Configures <see cref="IMvcCoreBuilder" /> to support runtime compilation of Razor views and Razor Pages.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder" />.</param>
/// <param name="setupAction">An action to configure the <see cref="MvcRazorRuntimeCompilationOptions"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddRazorRuntimeCompilation(this IMvcCoreBuilder builder, Action<MvcRazorRuntimeCompilationOptions> setupAction)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (setupAction == null)
{
throw new ArgumentNullException(nameof(setupAction));
}
AddServices(builder.Services);
builder.Services.Configure(setupAction);
return builder;
}
// Internal for testing.
internal static void AddServices(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcRazorRuntimeCompilationOptions>, MvcRazorRuntimeCompilationOptionsSetup>());
var compilerProvider = services.FirstOrDefault(f =>
f.ServiceType == typeof(IViewCompilerProvider) &&
f.ImplementationType?.Assembly == typeof(IViewCompilerProvider).Assembly &&
f.ImplementationType.FullName == "Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompilerProvider");
if (compilerProvider != null)
{
// Replace the default implementation of IViewCompilerProvider
services.Remove(compilerProvider);
}
services.TryAddSingleton<IViewCompilerProvider, RuntimeViewCompilerProvider>();
var actionDescriptorProvider = services.FirstOrDefault(f =>
f.ServiceType == typeof(IActionDescriptorProvider) &&
f.ImplementationType == typeof(CompiledPageActionDescriptorProvider));
if (actionDescriptorProvider != null)
{
// RuntimeCompilation registers an instance of PageActionDescriptorProvider(PageADP). CompiledPageADP and runtime compilation
// cannot co-exist since CompiledPageADP will attempt to resolve action descriptors for lazily compiled views (such as for
// ones from non-physical file providers). We'll instead remove CompiledPageActionDescriptors from the DI container if present.
services.Remove(actionDescriptorProvider);
}
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IActionDescriptorProvider, PageActionDescriptorProvider>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<MatcherPolicy, PageLoaderMatcherPolicy>());
services.TryAddSingleton<RuntimeCompilationFileProvider>();
services.TryAddSingleton<RazorReferenceManager>();
services.TryAddSingleton<CSharpCompiler>();
services.TryAddSingleton<RazorProjectFileSystem, FileProviderRazorProjectFileSystem>();
services.TryAddSingleton(s =>
{
var fileSystem = s.GetRequiredService<RazorProjectFileSystem>();
var csharpCompiler = s.GetRequiredService<CSharpCompiler>();
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder =>
{
RazorExtensions.Register(builder);
// Roslyn + TagHelpers infrastructure
var referenceManager = s.GetRequiredService<RazorReferenceManager>();
builder.Features.Add(new LazyMetadataReferenceFeature(referenceManager));
builder.Features.Add(new CompilationTagHelperFeature());
// TagHelperDescriptorProviders (actually do tag helper discovery)
builder.Features.Add(new DefaultTagHelperDescriptorProvider());
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
builder.SetCSharpLanguageVersion(csharpCompiler.ParseOptions.LanguageVersion);
});
return projectEngine;
});
//
// Razor Pages
//
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IPageRouteModelProvider, RazorProjectPageRouteModelProvider>());
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IActionDescriptorChangeProvider, PageActionDescriptorChangeProvider>());
}
}