Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #11904 TypeFeatureProvider throws if a Razor Page has no PageModel #11905

Merged
merged 2 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.Demo/Pages/HelloWorld.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@page "/helloworld"

@functions
{
public Task<IActionResult> OnGetAsync()
{
return Task.FromResult<IActionResult>(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 })

<h2>Hello World from @ViewContext.RouteData.Values["page"]</h2>

<p>
@message
</p>
<p>
Date using the DateTimeShape: @await DisplayAsync(await New.DateTime(Utc: null, Format: T["MMMM dd, yyyy"].Value))
</p>
Original file line number Diff line number Diff line change
@@ -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<IFeatureInfo> _features;
private readonly ITypeFeatureProvider _typeFeatureProvider;
private readonly ILookup<string, string> _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;
Expand All @@ -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<FeatureAttribute>(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;
}
}
}