From 314aa366e145bb9dd4537404629e6fa2d0a2bae1 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 7 Feb 2017 14:24:12 -0800 Subject: [PATCH] Add TempData property support for Pages --- samples/MvcSandbox/Pages/Index.cshtml | 12 +++- samples/MvcSandbox/Startup.cs | 2 +- .../MvcRazorPagesMvcCoreBuilderExtensions.cs | 4 ++ .../PageActionDescriptorProvider.cs | 4 ++ .../TempDataPropertyProvider.cs | 63 +++++++++++++++++++ .../Internal/PageActionInvoker.cs | 23 +++++++ .../Internal/PageActionInvokerProvider.cs | 4 ++ .../TempDataAttribute.cs | 13 ++++ .../Internal/ISaveTempDataCallback.cs | 12 ++++ .../Internal/SaveTempDataFilter.cs | 38 ++++++++--- .../Internal/SaveTempDataPropertyFilter.cs | 35 +++++++++++ .../MvcSandboxTest.cs | 2 +- .../PageActionDescriptorProviderTest.cs | 62 +++++++++++++++++- .../Internal/PageActionInvokerProviderTest.cs | 1 + .../Internal/PageActionInvokerTest.cs | 1 + 15 files changed, 263 insertions(+), 13 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/TempDataPropertyProvider.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.RazorPages/TempDataAttribute.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ISaveTempDataCallback.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs diff --git a/samples/MvcSandbox/Pages/Index.cshtml b/samples/MvcSandbox/Pages/Index.cshtml index 702b1005ce..207eaa2591 100644 --- a/samples/MvcSandbox/Pages/Index.cshtml +++ b/samples/MvcSandbox/Pages/Index.cshtml @@ -1,12 +1,22 @@ @page Test @model TestModel +@functions { + + [TempData] + public string Message { get; set; } +} +

RazorPages says Hello @Model.Name!

    -
  • This file should give you a quick view of a Mvc Raor Page in action.
  • +
  • This file should give you a quick view of a Mvc Razor Page in action.
+

Message from TempData: @Message

+ @{ + Message = $"You visited this page at {DateTime.Now}."; + }
diff --git a/samples/MvcSandbox/Startup.cs b/samples/MvcSandbox/Startup.cs index 1984d71708..748aa8d517 100644 --- a/samples/MvcSandbox/Startup.cs +++ b/samples/MvcSandbox/Startup.cs @@ -16,7 +16,7 @@ namespace MvcSandbox // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc(); + services.AddMvc().AddCookieTempDataProvider(); services.Insert(0, ServiceDescriptor.Singleton( typeof(IConfigureOptions), diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs index cd8e3de42f..974dfb8ff5 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs @@ -66,8 +66,12 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + + services.TryAddSingleton(); } } } diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs index b9333afe6c..c748673790 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.Extensions.Options; @@ -84,6 +85,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure model.Selectors.Add(CreateSelectorModel(parentDirectoryPath, template)); } + model.Filters.Add(new SaveTempDataPropertyFilter()); // Support for [TempData] on properties + model.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); // Always require an antiforgery token on post + for (var i = 0; i < _pagesOptions.Conventions.Count; i++) { _pagesOptions.Conventions[i].Apply(model); diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/TempDataPropertyProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/TempDataPropertyProvider.cs new file mode 100644 index 0000000000..12c20e265e --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/TempDataPropertyProvider.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewFeatures; + +namespace Microsoft.AspNetCore.Mvc.RazorPages +{ + public class TempDataPropertyProvider + { + public static readonly string Prefix = "TempDataProperty-"; + + private ConcurrentDictionary> _subjectProperties = + new ConcurrentDictionary>(); + + public IDictionary LoadAndTrackChanges(object subject, ITempDataDictionary tempData) + { + var properties = GetSubjectProperties(subject); + var result = new Dictionary(); + + foreach (var property in properties) + { + var value = tempData[Prefix + property.Name]; + + result[property] = value; + + // TODO: Clarify what behavior should be for null values here + if (value != null && property.PropertyType.IsAssignableFrom(value.GetType())) + { + property.SetValue(subject, value); + } + } + + return result; + } + + private IEnumerable GetSubjectProperties(object subject) + { + return _subjectProperties.GetOrAdd(subject.GetType(), subjectType => + { + var properties = subjectType.GetRuntimeProperties() + .Where(pi => pi.GetCustomAttribute() != null); + + if (properties.Any(pi => !(pi.SetMethod != null && pi.SetMethod.IsPublic && pi.GetMethod != null && pi.GetMethod.IsPublic))) + { + throw new InvalidOperationException("TempData properties must have a public getter and setter."); + } + + if (properties.Any(pi => !(pi.PropertyType.GetTypeInfo().IsPrimitive || pi.PropertyType == typeof(string)))) + { + throw new InvalidOperationException("TempData properties must be declared as primitive types or string only."); + } + + return properties; + }); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs index 15f39db944..2db01fdc7d 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; +using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal @@ -21,6 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal { private readonly IPageHandlerMethodSelector _selector; private readonly PageContext _pageContext; + private readonly TempDataPropertyProvider _propertyProvider; private Page _page; private object _model; @@ -28,6 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal public PageActionInvoker( IPageHandlerMethodSelector handlerMethodSelector, + TempDataPropertyProvider propertyProvider, DiagnosticSource diagnosticSource, ILogger logger, PageContext pageContext, @@ -42,6 +45,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal valueProviderFactories) { _selector = handlerMethodSelector; + _propertyProvider = propertyProvider; _pageContext = pageContext; CacheEntry = cacheEntry; } @@ -337,6 +341,25 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal _pageContext.ViewData.Model = _model; } + // This is a workaround for not yet having proper filter for Pages. + SaveTempDataPropertyFilter propertyFilter = null; + for (var i = 0; i < _filters.Length; i++) + { + propertyFilter = _filters[i] as SaveTempDataPropertyFilter; + if (propertyFilter != null) + { + break; + } + } + + var originalValues = _propertyProvider.LoadAndTrackChanges(_page, _pageContext.TempData); + if (propertyFilter != null) + { + propertyFilter.OriginalValues = originalValues; + propertyFilter.Subject = _page; + propertyFilter.Prefix = TempDataPropertyProvider.Prefix; + } + IActionResult result = null; var handler = _selector.Select(_pageContext); diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvokerProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvokerProvider.cs index b0ccfb16fa..3119c501a5 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvokerProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvokerProvider.cs @@ -36,6 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal private readonly ITempDataDictionaryFactory _tempDataFactory; private readonly HtmlHelperOptions _htmlHelperOptions; private readonly IPageHandlerMethodSelector _selector; + private readonly TempDataPropertyProvider _propertyProvider; private readonly RazorProject _razorProject; private readonly DiagnosticSource _diagnosticSource; private readonly ILogger _logger; @@ -53,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal IOptions mvcOptions, IOptions htmlHelperOptions, IPageHandlerMethodSelector selector, + TempDataPropertyProvider propertyProvider, RazorProject razorProject, DiagnosticSource diagnosticSource, ILoggerFactory loggerFactory) @@ -68,6 +70,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal _tempDataFactory = tempDataFactory; _htmlHelperOptions = htmlHelperOptions.Value; _selector = selector; + _propertyProvider = propertyProvider; _razorProject = razorProject; _diagnosticSource = diagnosticSource; _logger = loggerFactory.CreateLogger(); @@ -149,6 +152,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal return new PageActionInvoker( _selector, + _propertyProvider, _diagnosticSource, _logger, pageContext, diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/TempDataAttribute.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/TempDataAttribute.cs new file mode 100644 index 0000000000..938861eb7c --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/TempDataAttribute.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Mvc.Rendering +{ + [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] + public sealed class TempDataAttribute : Attribute + { + + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ISaveTempDataCallback.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ISaveTempDataCallback.cs new file mode 100644 index 0000000000..6f3aa16493 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ISaveTempDataCallback.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal +{ + public interface ISaveTempDataCallback : IFilterMetadata + { + void OnTempDataSaving(ITempDataDictionary tempData); + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataFilter.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataFilter.cs index 912c7c7131..f5ca08c3ab 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataFilter.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataFilter.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Internal; @@ -49,15 +50,17 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal SaveTempData( result: null, factory: saveTempDataContext.TempDataDictionaryFactory, + filters: saveTempDataContext.Filters, httpContext: saveTempDataContext.HttpContext); return TaskCache.CompletedTask; }, - state: new SaveTempDataContext() - { - HttpContext = context.HttpContext, - TempDataDictionaryFactory = _factory - }); + state: new SaveTempDataContext() + { + Filters = context.Filters, + HttpContext = context.HttpContext, + TempDataDictionaryFactory = _factory + }); } } @@ -79,7 +82,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal // late in the pipeline at which point SessionFeature would not be available. if (!context.HttpContext.Response.HasStarted) { - SaveTempData(context.Result, _factory, context.HttpContext); + SaveTempData(context.Result, _factory, context.Filters, context.HttpContext); // If SaveTempDataFilter got added twice this might already be in there. if (!context.HttpContext.Items.ContainsKey(TempDataSavedKey)) { @@ -88,17 +91,34 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal } } - private static void SaveTempData(IActionResult result, ITempDataDictionaryFactory factory, HttpContext httpContext) + private static void SaveTempData( + IActionResult result, + ITempDataDictionaryFactory factory, + IList filters, + HttpContext httpContext) { + var tempData = factory.GetTempData(httpContext); + + for (var i = 0; i < filters.Count; i++) + { + var callback = filters[i] as ISaveTempDataCallback; + if (callback != null) + { + callback.OnTempDataSaving(tempData); + } + } + if (result is IKeepTempDataResult) { - factory.GetTempData(httpContext).Keep(); + tempData.Keep(); } - factory.GetTempData(httpContext).Save(); + + tempData.Save(); } private class SaveTempDataContext { + public IList Filters { get; set; } public HttpContext HttpContext { get; set; } public ITempDataDictionaryFactory TempDataDictionaryFactory { get; set; } } diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs new file mode 100644 index 0000000000..82b794e143 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Reflection; + +namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal +{ + public class SaveTempDataPropertyFilter : ISaveTempDataCallback + { + public string Prefix { get; set; } + + public object Subject { get; set; } + + public IDictionary OriginalValues { get; set; } + + public void OnTempDataSaving(ITempDataDictionary tempData) + { + if (Subject != null && OriginalValues != null) + { + foreach (var kvp in OriginalValues) + { + var property = kvp.Key; + var originalValue = kvp.Value; + + var newValue = property.GetValue(Subject); + if (newValue != null && newValue != originalValue) + { + tempData[Prefix + property.Name] = newValue; + } + } + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/MvcSandboxTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/MvcSandboxTest.cs index 5b5b2f1196..f5caba2d6a 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/MvcSandboxTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/MvcSandboxTest.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests var response = await Client.GetStringAsync("http://localhost/Pages/Test"); // Assert - Assert.Contains("This file should give you a quick view of a Mvc Raor Page in action.", response); + Assert.Contains("This file should give you a quick view of a Mvc Razor Page in action.", response); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs index 7d2b91048b..d023636248 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor.Internal; +using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.Extensions.Options; using Moq; @@ -193,6 +194,44 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure }); } + [Fact] + public void GetDescriptors_ImplicitFilters() + { + // Arrange + var options = new MvcOptions(); + var razorProject = new Mock(); + razorProject.Setup(p => p.EnumerateItems("/")) + .Returns(new[] + { + GetProjectItem("/", "/Home.cshtml", $"@page {Environment.NewLine}"), + }); + var provider = new PageActionDescriptorProvider( + razorProject.Object, + GetAccessor(options), + GetAccessor()); + var context = new ActionDescriptorProviderContext(); + + // Act + provider.OnProvidersExecuting(context); + + // Assert + var result = Assert.Single(context.Results); + var descriptor = Assert.IsType(result); + Assert.Collection( + descriptor.FilterDescriptors, + filterDescriptor => + { + Assert.Equal(FilterScope.Action, filterDescriptor.Scope); + Assert.IsType(filterDescriptor.Filter); + }, + filterDescriptor => + { + Assert.Equal(FilterScope.Action, filterDescriptor.Scope); + Assert.IsType(filterDescriptor.Filter); + }); + } + + [Fact] public void GetDescriptors_AddsGlobalFilters() { @@ -220,7 +259,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure // Assert var result = Assert.Single(context.Results); var descriptor = Assert.IsType(result); - Assert.Collection(descriptor.FilterDescriptors, + Assert.Collection( + descriptor.FilterDescriptors, filterDescriptor => { Assert.Equal(FilterScope.Global, filterDescriptor.Scope); @@ -230,6 +270,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure { Assert.Equal(FilterScope.Global, filterDescriptor.Scope); Assert.Same(filter2, filterDescriptor.Filter); + }, + filterDescriptor => + { + Assert.Equal(FilterScope.Action, filterDescriptor.Scope); + Assert.IsType(filterDescriptor.Filter); + }, + filterDescriptor => + { + Assert.Equal(FilterScope.Action, filterDescriptor.Scope); + Assert.IsType(filterDescriptor.Filter); }); } @@ -275,6 +325,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure Assert.Same(globalFilter, filterDescriptor.Filter); }, filterDescriptor => + { + Assert.Equal(FilterScope.Action, filterDescriptor.Scope); + Assert.IsType(filterDescriptor.Filter); + }, + filterDescriptor => + { + Assert.Equal(FilterScope.Action, filterDescriptor.Scope); + Assert.IsType(filterDescriptor.Filter); + }, + filterDescriptor => { Assert.Equal(FilterScope.Action, filterDescriptor.Scope); Assert.Same(localFilter, filterDescriptor.Filter); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs index 1616c1112d..a9d639d390 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs @@ -283,6 +283,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal new TestOptionsManager(), new TestOptionsManager(), Mock.Of(), + new TempDataPropertyProvider(), razorProject, new DiagnosticListener("Microsoft.AspNetCore"), NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs index 37c391b916..c4aa41b3c7 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs @@ -607,6 +607,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal var invoker = new PageActionInvoker( selector, + new TempDataPropertyProvider(), diagnosticSource, logger, pageContext,