| File: ApplicationModels\CompiledPageRouteModelProvider.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.RazorPages\src\Microsoft.AspNetCore.Mvc.RazorPages.csproj (Microsoft.AspNetCore.Mvc.RazorPages) |
// 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.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Razor.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.ApplicationModels; #pragma warning disable CA1852 // Seal internal types internal class CompiledPageRouteModelProvider : IPageRouteModelProvider #pragma warning restore CA1852 // Seal internal types { private const string RazorPageDocumentKind = "mvc.1.0.razor-page"; private const string RouteTemplateKey = "RouteTemplate"; private readonly ApplicationPartManager _applicationManager; private readonly RazorPagesOptions _pagesOptions; private readonly PageRouteModelFactory _routeModelFactory; public CompiledPageRouteModelProvider( ApplicationPartManager applicationManager, IOptions<RazorPagesOptions> pagesOptionsAccessor, ILogger<CompiledPageRouteModelProvider> logger) { _applicationManager = applicationManager ?? throw new ArgumentNullException(nameof(applicationManager)); _pagesOptions = pagesOptionsAccessor?.Value ?? throw new ArgumentNullException(nameof(pagesOptionsAccessor)); _routeModelFactory = new PageRouteModelFactory(_pagesOptions, logger); } public int Order => -1000; public void OnProvidersExecuting(PageRouteModelProviderContext context) { ArgumentNullException.ThrowIfNull(context); CreateModels(context); } public void OnProvidersExecuted(PageRouteModelProviderContext context) { ArgumentNullException.ThrowIfNull(context); } private IEnumerable<CompiledViewDescriptor> GetViewDescriptors(ApplicationPartManager applicationManager) { ArgumentNullException.ThrowIfNull(applicationManager); var viewsFeature = GetViewFeature(applicationManager); var visited = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (var viewDescriptor in viewsFeature.ViewDescriptors) { if (!visited.Add(viewDescriptor.RelativePath)) { // Already seen an descriptor with a higher "order" continue; } if (IsRazorPage(viewDescriptor)) { yield return viewDescriptor; } } static bool IsRazorPage(CompiledViewDescriptor viewDescriptor) { if (viewDescriptor.Item != null) { return viewDescriptor.Item.Kind == RazorPageDocumentKind; } return false; } } protected virtual ViewsFeature GetViewFeature(ApplicationPartManager applicationManager) { var viewsFeature = new ViewsFeature(); applicationManager.PopulateFeature(viewsFeature); return viewsFeature; } private void CreateModels(PageRouteModelProviderContext context) { var rootDirectory = _pagesOptions.RootDirectory; if (!rootDirectory.EndsWith("/", StringComparison.Ordinal)) { rootDirectory = rootDirectory + "/"; } var areaRootDirectory = "/Areas/"; foreach (var viewDescriptor in GetViewDescriptors(_applicationManager)) { var relativePath = viewDescriptor.RelativePath; var routeTemplate = GetRouteTemplate(viewDescriptor); PageRouteModel? routeModel = null; // When RootDirectory and AreaRootDirectory overlap (e.g. RootDirectory = '/', AreaRootDirectory = '/Areas'), we // only want to allow a page to be associated with the area route. if (relativePath.StartsWith(areaRootDirectory, StringComparison.OrdinalIgnoreCase)) { routeModel = _routeModelFactory.CreateAreaRouteModel(relativePath, routeTemplate); } else if (relativePath.StartsWith(rootDirectory, StringComparison.OrdinalIgnoreCase)) { routeModel = _routeModelFactory.CreateRouteModel(relativePath, routeTemplate); } if (routeModel != null) { context.RouteModels.Add(routeModel); } } } internal static string? GetRouteTemplate(CompiledViewDescriptor viewDescriptor) { if (viewDescriptor.Item != null) { return viewDescriptor.Item.Metadata .OfType<RazorCompiledItemMetadataAttribute>() .FirstOrDefault(f => f.Key == RouteTemplateKey) ?.Value; } return null; } }