Skip to content

Commit

Permalink
Fixes #11904 TypeFeatureProvider throws if a Razor Page has no PageMo…
Browse files Browse the repository at this point in the history
…del (#11905)

* Update ModularPageApplicationModelProvider.cs

* Create HelloWorld.cshtml
  • Loading branch information
jtkech authored Jun 30, 2022
1 parent 3cd619b commit e11e4e8
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 36 deletions.
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;
}
}
}

0 comments on commit e11e4e8

Please sign in to comment.