From e11e4e888dd3564553513ded30e89c636ec27268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Thierry=20K=C3=A9chichian?= Date: Thu, 30 Jun 2022 21:18:01 +0200 Subject: [PATCH] Fixes #11904 TypeFeatureProvider throws if a Razor Page has no PageModel (#11905) * Update ModularPageApplicationModelProvider.cs * Create HelloWorld.cshtml --- .../OrchardCore.Demo/Pages/HelloWorld.cshtml | 25 +++++++++ .../ModularPageApplicationModelProvider.cs | 52 ++++++------------- 2 files changed, 41 insertions(+), 36 deletions(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.Demo/Pages/HelloWorld.cshtml diff --git a/src/OrchardCore.Modules/OrchardCore.Demo/Pages/HelloWorld.cshtml b/src/OrchardCore.Modules/OrchardCore.Demo/Pages/HelloWorld.cshtml new file mode 100644 index 00000000000..abce3c19d0b --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Demo/Pages/HelloWorld.cshtml @@ -0,0 +1,25 @@ +@page "/helloworld" + +@functions +{ + public Task OnGetAsync() + { + return Task.FromResult(Page()); + } +} + +@{ + var title = "This is a razor 'Page' coming from OrchardCore.Demo that doesn't define any 'PageModel'."; + var message = $"Date and time on the server: { DateTime.Now.ToString() }"; +} + +@await Html.PartialAsync("Header", new { Title = title }) + +

Hello World from @ViewContext.RouteData.Values["page"]

+ +

+ @message +

+

+ Date using the DateTimeShape: @await DisplayAsync(await New.DateTime(Utc: null, Format: T["MMMM dd, yyyy"].Value)) +

diff --git a/src/OrchardCore/OrchardCore.Mvc.Core/RazorPages/ModularPageApplicationModelProvider.cs b/src/OrchardCore/OrchardCore.Mvc.Core/RazorPages/ModularPageApplicationModelProvider.cs index e9e621bc4c3..36a442a2093 100644 --- a/src/OrchardCore/OrchardCore.Mvc.Core/RazorPages/ModularPageApplicationModelProvider.cs +++ b/src/OrchardCore/OrchardCore.Mvc.Core/RazorPages/ModularPageApplicationModelProvider.cs @@ -1,28 +1,25 @@ using System; -using System.Collections.Generic; using System.Linq; +using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationModels; using OrchardCore.Environment.Extensions; -using OrchardCore.Environment.Extensions.Features; using OrchardCore.Environment.Shell.Descriptor.Models; +using OrchardCore.Modules; namespace OrchardCore.Mvc.RazorPages { public class ModularPageApplicationModelProvider : IPageApplicationModelProvider { - private IEnumerable _features; - private readonly ITypeFeatureProvider _typeFeatureProvider; + private readonly ILookup _featureIdsByArea; public ModularPageApplicationModelProvider( - ITypeFeatureProvider typeFeatureProvider, IExtensionManager extensionManager, ShellDescriptor shellDescriptor) { - // Available features in the current shell. - _features = extensionManager.GetFeatures().Where(f => shellDescriptor.Features.Any(sf => - sf.Id == f.Id)).Select(f => f); - - _typeFeatureProvider = typeFeatureProvider; + // Available features by area in the current shell. + _featureIdsByArea = extensionManager.GetFeatures() + .Where(f => shellDescriptor.Features.Any(sf => sf.Id == f.Id)) + .ToLookup(f => f.Extension.Id, f => f.Id); } public int Order => -1000 + 10; @@ -34,40 +31,23 @@ public void OnProvidersExecuting(PageApplicationModelProviderContext context) // Called the 1st time a page is requested or if any page has been updated. public void OnProvidersExecuted(PageApplicationModelProviderContext context) { - // Check if the page belongs to an enabled module. - var relativePath = context.ActionDescriptor.RelativePath; + // Check if the page belongs to an enabled feature. var found = false; - var featureForPath = _features.Where(f => - relativePath.StartsWith('/' + f.Extension.SubPath + "/Pages/", StringComparison.Ordinal)) - .OrderBy(f => f.Id == f.Extension.Id ? 1 : 0).ToArray(); - // All pages with internal model types are available to module - var pageModelType = context.PageApplicationModel.ModelType.AsType(); - if (!IsComponentType(pageModelType)) - { - found = featureForPath.Any(f => f.Id == f.Extension.Id); - } - else + var area = context.PageApplicationModel.AreaName; + if (_featureIdsByArea.Contains(area)) { - // Pages with public model types containing [Feature] attribute - // are available only if feature is enabled - foreach (var feature in featureForPath) + found = true; + + var pageModelType = context.PageApplicationModel.ModelType.AsType(); + var attribute = pageModelType.GetCustomAttributes(false).FirstOrDefault(); + if (attribute != null) { - var blueprint = _typeFeatureProvider.GetFeatureForDependency(pageModelType); - if (blueprint != null && feature.Id == blueprint.Id) - { - found = true; - break; - } + found = _featureIdsByArea[area].Contains(attribute.FeatureName); } } context.PageApplicationModel.Filters.Add(new ModularPageViewEnginePathFilter(found)); } - - private bool IsComponentType(Type type) - { - return type.IsClass && !type.IsAbstract && type.IsPublic; - } } }