| File: PageDirectiveFeature.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.Razor.RuntimeCompilation\src\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.csproj (Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Mvc.Razor.Extensions; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; internal static partial class PageDirectiveFeature { private static readonly RazorProjectEngine PageDirectiveEngine = RazorProjectEngine.Create(RazorConfiguration.Default, new EmptyRazorProjectFileSystem(), builder => { for (var i = builder.Phases.Count - 1; i >= 0; i--) { var phase = builder.Phases[i]; builder.Phases.RemoveAt(i); if (phase is IRazorDocumentClassifierPhase) { break; } } RazorExtensions.Register(builder); builder.Features.Add(new PageDirectiveParserOptionsFeature()); }); public static bool TryGetPageDirective(ILogger logger, RazorProjectItem projectItem, [NotNullWhen(true)] out string? template) { ArgumentNullException.ThrowIfNull(projectItem); var codeDocument = PageDirectiveEngine.Process(projectItem); var documentIRNode = codeDocument.GetDocumentIntermediateNode(); if (PageDirective.TryGetPageDirective(documentIRNode, out var pageDirective)) { if (pageDirective.DirectiveNode is MalformedDirectiveIntermediateNode malformedNode) { Log.MalformedPageDirective(logger, projectItem.FilePath, malformedNode.Diagnostics); } template = pageDirective.RouteTemplate; return true; } template = null; return false; } private sealed class PageDirectiveParserOptionsFeature : RazorEngineFeatureBase, IConfigureRazorParserOptionsFeature { public int Order { get; } public void Configure(RazorParserOptionsBuilder options) { options.ParseLeadingDirectives = true; } } private sealed class EmptyRazorProjectFileSystem : RazorProjectFileSystem { public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath) { return Enumerable.Empty<RazorProjectItem>(); } public override IEnumerable<RazorProjectItem> FindHierarchicalItems(string basePath, string path, string fileName) { return Enumerable.Empty<RazorProjectItem>(); } public override RazorProjectItem GetItem(string path) { return GetItem(path, fileKind: null); } public override RazorProjectItem GetItem(string path, string? fileKind) { return new NotFoundProjectItem(string.Empty, path, fileKind); } private sealed class NotFoundProjectItem : RazorProjectItem { public NotFoundProjectItem(string basePath, string path, string? fileKind) { BasePath = basePath; FilePath = path; FileKind = fileKind ?? FileKinds.GetFileKindFromFilePath(FilePath); } /// <inheritdoc /> public override string BasePath { get; } /// <inheritdoc /> public override string FilePath { get; } /// <inheritdoc /> public override string FileKind { get; } /// <inheritdoc /> public override bool Exists => false; /// <inheritdoc /> public override string PhysicalPath => throw new NotSupportedException(); /// <inheritdoc /> public override Stream Read() => throw new NotSupportedException(); } } private static partial class Log { [LoggerMessage(104, LogLevel.Warning, "The page directive at '{FilePath}' is malformed. Please fix the following issues: {Diagnostics}", EventName = "MalformedPageDirective", SkipEnabledCheck = true)] private static partial void MalformedPageDirective(ILogger logger, string filePath, string[] diagnostics); public static void MalformedPageDirective(ILogger logger, string filePath, IList<RazorDiagnostic> diagnostics) { if (logger.IsEnabled(LogLevel.Warning)) { var messages = new string[diagnostics.Count]; for (var i = 0; i < diagnostics.Count; i++) { messages[i] = diagnostics[i].GetMessage(CultureInfo.CurrentCulture); } MalformedPageDirective(logger, filePath, messages); } } } }