| File: Infrastructure\DefaultPageLoader.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.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; internal sealed class DefaultPageLoader : PageLoader { private readonly IViewCompilerProvider _viewCompilerProvider; private readonly CompiledPageActionDescriptorFactory _compiledPageActionDescriptorFactory; private readonly ActionEndpointFactory _endpointFactory; public DefaultPageLoader( IEnumerable<IPageApplicationModelProvider> applicationModelProviders, IViewCompilerProvider viewCompilerProvider, ActionEndpointFactory endpointFactory, IOptions<RazorPagesOptions> pageOptions, IOptions<MvcOptions> mvcOptions) { _viewCompilerProvider = viewCompilerProvider; _endpointFactory = endpointFactory; _compiledPageActionDescriptorFactory = new CompiledPageActionDescriptorFactory(applicationModelProviders, mvcOptions.Value, pageOptions.Value); } private IViewCompiler Compiler => _viewCompilerProvider.GetCompiler(); [Obsolete] public override Task<CompiledPageActionDescriptor> LoadAsync(PageActionDescriptor actionDescriptor) => LoadAsync(actionDescriptor, EndpointMetadataCollection.Empty); public override Task<CompiledPageActionDescriptor> LoadAsync(PageActionDescriptor actionDescriptor, EndpointMetadataCollection endpointMetadata) { ArgumentNullException.ThrowIfNull(actionDescriptor); if (actionDescriptor is CompiledPageActionDescriptor compiledPageActionDescriptor) { // It's possible for some code paths of PageLoaderMatcherPolicy to invoke LoadAsync with an instance // of CompiledPageActionDescriptor. In that case, we'll return the instance as-is. compiledPageActionDescriptor.CompiledPageActionDescriptorTask ??= Task.FromResult(compiledPageActionDescriptor); return compiledPageActionDescriptor.CompiledPageActionDescriptorTask; } var task = actionDescriptor.CompiledPageActionDescriptorTask; if (task != null) { return task; } return actionDescriptor.CompiledPageActionDescriptorTask = LoadAsyncCore(actionDescriptor, endpointMetadata); } private async Task<CompiledPageActionDescriptor> LoadAsyncCore(PageActionDescriptor actionDescriptor, EndpointMetadataCollection endpointMetadata) { var viewDescriptor = await Compiler.CompileAsync(actionDescriptor.RelativePath); var compiled = _compiledPageActionDescriptorFactory.CreateCompiledDescriptor(actionDescriptor, viewDescriptor); var endpoints = new List<Endpoint>(); _endpointFactory.AddEndpoints( endpoints, routeNames: new HashSet<string>(StringComparer.OrdinalIgnoreCase), action: compiled, routes: Array.Empty<ConventionalRouteEntry>(), conventions: new Action<EndpointBuilder>[] { b => { // Copy Endpoint metadata for PageActionActionDescriptor to the compiled one. // This is particularly important for the runtime compiled scenario where endpoint metadata is added // to the PageActionDescriptor, which needs to be accounted for when constructing the // CompiledPageActionDescriptor as part of the one of the many matcher policies. // Metadata from PageActionDescriptor is less significant than the one discovered from the compiled type. // Consequently, we'll insert it at the beginning. for (var i = endpointMetadata.Count - 1; i >=0; i--) { b.Metadata.Insert(0, endpointMetadata[i]); } }, }, groupConventions: Array.Empty<Action<EndpointBuilder>>(), finallyConventions: Array.Empty<Action<EndpointBuilder>>(), groupFinallyConventions: Array.Empty<Action<EndpointBuilder>>(), createInertEndpoints: false); // In some test scenarios there's no route so the endpoint isn't created. This is fine because // it won't happen for real. compiled.Endpoint = endpoints.SingleOrDefault(); return compiled; } }