Add TempData property support for Pages
This commit is contained in:
parent
690ef186a3
commit
314aa366e1
|
|
@ -1,12 +1,22 @@
|
||||||
@page Test
|
@page Test
|
||||||
@model TestModel
|
@model TestModel
|
||||||
|
|
||||||
|
@functions {
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<h2>RazorPages says Hello @Model.Name!</h2>
|
<h2>RazorPages says Hello @Model.Name!</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>This file should give you a quick view of a Mvc Raor Page in action.</li>
|
<li>This file should give you a quick view of a Mvc Razor Page in action.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<p>Message from TempData: @Message</p>
|
||||||
|
@{
|
||||||
|
Message = $"You visited this page at {DateTime.Now}.";
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace MvcSandbox
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddMvc();
|
services.AddMvc().AddCookieTempDataProvider();
|
||||||
|
|
||||||
services.Insert(0, ServiceDescriptor.Singleton(
|
services.Insert(0, ServiceDescriptor.Singleton(
|
||||||
typeof(IConfigureOptions<AntiforgeryOptions>),
|
typeof(IConfigureOptions<AntiforgeryOptions>),
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.TryAddSingleton<IPageLoader, DefaultPageLoader>();
|
services.TryAddSingleton<IPageLoader, DefaultPageLoader>();
|
||||||
services.TryAddSingleton<IPageHandlerMethodSelector, DefaultPageHandlerMethodSelector>();
|
services.TryAddSingleton<IPageHandlerMethodSelector, DefaultPageHandlerMethodSelector>();
|
||||||
services.TryAddSingleton<PageResultExecutor>();
|
services.TryAddSingleton<PageResultExecutor>();
|
||||||
|
|
||||||
services.TryAddSingleton<PageArgumentBinder, DefaultPageArgumentBinder>();
|
services.TryAddSingleton<PageArgumentBinder, DefaultPageArgumentBinder>();
|
||||||
|
|
||||||
services.TryAddSingleton<IActionDescriptorChangeProvider, PageActionDescriptorChangeProvider>();
|
services.TryAddSingleton<IActionDescriptorChangeProvider, PageActionDescriptorChangeProvider>();
|
||||||
|
|
||||||
|
services.TryAddSingleton<TempDataPropertyProvider>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.Routing;
|
using Microsoft.AspNetCore.Mvc.Routing;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.AspNetCore.Razor.Evolution;
|
using Microsoft.AspNetCore.Razor.Evolution;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
|
@ -84,6 +85,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
model.Selectors.Add(CreateSelectorModel(parentDirectoryPath, template));
|
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++)
|
for (var i = 0; i < _pagesOptions.Conventions.Count; i++)
|
||||||
{
|
{
|
||||||
_pagesOptions.Conventions[i].Apply(model);
|
_pagesOptions.Conventions[i].Apply(model);
|
||||||
|
|
|
||||||
|
|
@ -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<Type, IEnumerable<PropertyInfo>> _subjectProperties =
|
||||||
|
new ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>();
|
||||||
|
|
||||||
|
public IDictionary<PropertyInfo, object> LoadAndTrackChanges(object subject, ITempDataDictionary tempData)
|
||||||
|
{
|
||||||
|
var properties = GetSubjectProperties(subject);
|
||||||
|
var result = new Dictionary<PropertyInfo, object>();
|
||||||
|
|
||||||
|
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<PropertyInfo> GetSubjectProperties(object subject)
|
||||||
|
{
|
||||||
|
return _subjectProperties.GetOrAdd(subject.GetType(), subjectType =>
|
||||||
|
{
|
||||||
|
var properties = subjectType.GetRuntimeProperties()
|
||||||
|
.Where(pi => pi.GetCustomAttribute<TempDataAttribute>() != 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
|
@ -21,6 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
private readonly IPageHandlerMethodSelector _selector;
|
private readonly IPageHandlerMethodSelector _selector;
|
||||||
private readonly PageContext _pageContext;
|
private readonly PageContext _pageContext;
|
||||||
|
private readonly TempDataPropertyProvider _propertyProvider;
|
||||||
|
|
||||||
private Page _page;
|
private Page _page;
|
||||||
private object _model;
|
private object _model;
|
||||||
|
|
@ -28,6 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
|
||||||
public PageActionInvoker(
|
public PageActionInvoker(
|
||||||
IPageHandlerMethodSelector handlerMethodSelector,
|
IPageHandlerMethodSelector handlerMethodSelector,
|
||||||
|
TempDataPropertyProvider propertyProvider,
|
||||||
DiagnosticSource diagnosticSource,
|
DiagnosticSource diagnosticSource,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
PageContext pageContext,
|
PageContext pageContext,
|
||||||
|
|
@ -42,6 +45,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
valueProviderFactories)
|
valueProviderFactories)
|
||||||
{
|
{
|
||||||
_selector = handlerMethodSelector;
|
_selector = handlerMethodSelector;
|
||||||
|
_propertyProvider = propertyProvider;
|
||||||
_pageContext = pageContext;
|
_pageContext = pageContext;
|
||||||
CacheEntry = cacheEntry;
|
CacheEntry = cacheEntry;
|
||||||
}
|
}
|
||||||
|
|
@ -337,6 +341,25 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
_pageContext.ViewData.Model = _model;
|
_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;
|
IActionResult result = null;
|
||||||
|
|
||||||
var handler = _selector.Select(_pageContext);
|
var handler = _selector.Select(_pageContext);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
private readonly ITempDataDictionaryFactory _tempDataFactory;
|
private readonly ITempDataDictionaryFactory _tempDataFactory;
|
||||||
private readonly HtmlHelperOptions _htmlHelperOptions;
|
private readonly HtmlHelperOptions _htmlHelperOptions;
|
||||||
private readonly IPageHandlerMethodSelector _selector;
|
private readonly IPageHandlerMethodSelector _selector;
|
||||||
|
private readonly TempDataPropertyProvider _propertyProvider;
|
||||||
private readonly RazorProject _razorProject;
|
private readonly RazorProject _razorProject;
|
||||||
private readonly DiagnosticSource _diagnosticSource;
|
private readonly DiagnosticSource _diagnosticSource;
|
||||||
private readonly ILogger<PageActionInvoker> _logger;
|
private readonly ILogger<PageActionInvoker> _logger;
|
||||||
|
|
@ -53,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
IOptions<MvcOptions> mvcOptions,
|
IOptions<MvcOptions> mvcOptions,
|
||||||
IOptions<HtmlHelperOptions> htmlHelperOptions,
|
IOptions<HtmlHelperOptions> htmlHelperOptions,
|
||||||
IPageHandlerMethodSelector selector,
|
IPageHandlerMethodSelector selector,
|
||||||
|
TempDataPropertyProvider propertyProvider,
|
||||||
RazorProject razorProject,
|
RazorProject razorProject,
|
||||||
DiagnosticSource diagnosticSource,
|
DiagnosticSource diagnosticSource,
|
||||||
ILoggerFactory loggerFactory)
|
ILoggerFactory loggerFactory)
|
||||||
|
|
@ -68,6 +70,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
_tempDataFactory = tempDataFactory;
|
_tempDataFactory = tempDataFactory;
|
||||||
_htmlHelperOptions = htmlHelperOptions.Value;
|
_htmlHelperOptions = htmlHelperOptions.Value;
|
||||||
_selector = selector;
|
_selector = selector;
|
||||||
|
_propertyProvider = propertyProvider;
|
||||||
_razorProject = razorProject;
|
_razorProject = razorProject;
|
||||||
_diagnosticSource = diagnosticSource;
|
_diagnosticSource = diagnosticSource;
|
||||||
_logger = loggerFactory.CreateLogger<PageActionInvoker>();
|
_logger = loggerFactory.CreateLogger<PageActionInvoker>();
|
||||||
|
|
@ -149,6 +152,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
|
||||||
return new PageActionInvoker(
|
return new PageActionInvoker(
|
||||||
_selector,
|
_selector,
|
||||||
|
_propertyProvider,
|
||||||
_diagnosticSource,
|
_diagnosticSource,
|
||||||
_logger,
|
_logger,
|
||||||
pageContext,
|
pageContext,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Internal;
|
using Microsoft.AspNetCore.Mvc.Internal;
|
||||||
|
|
@ -49,15 +50,17 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
SaveTempData(
|
SaveTempData(
|
||||||
result: null,
|
result: null,
|
||||||
factory: saveTempDataContext.TempDataDictionaryFactory,
|
factory: saveTempDataContext.TempDataDictionaryFactory,
|
||||||
|
filters: saveTempDataContext.Filters,
|
||||||
httpContext: saveTempDataContext.HttpContext);
|
httpContext: saveTempDataContext.HttpContext);
|
||||||
|
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
},
|
},
|
||||||
state: new SaveTempDataContext()
|
state: new SaveTempDataContext()
|
||||||
{
|
{
|
||||||
HttpContext = context.HttpContext,
|
Filters = context.Filters,
|
||||||
TempDataDictionaryFactory = _factory
|
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.
|
// late in the pipeline at which point SessionFeature would not be available.
|
||||||
if (!context.HttpContext.Response.HasStarted)
|
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 SaveTempDataFilter got added twice this might already be in there.
|
||||||
if (!context.HttpContext.Items.ContainsKey(TempDataSavedKey))
|
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<IFilterMetadata> 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)
|
if (result is IKeepTempDataResult)
|
||||||
{
|
{
|
||||||
factory.GetTempData(httpContext).Keep();
|
tempData.Keep();
|
||||||
}
|
}
|
||||||
factory.GetTempData(httpContext).Save();
|
|
||||||
|
tempData.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SaveTempDataContext
|
private class SaveTempDataContext
|
||||||
{
|
{
|
||||||
|
public IList<IFilterMetadata> Filters { get; set; }
|
||||||
public HttpContext HttpContext { get; set; }
|
public HttpContext HttpContext { get; set; }
|
||||||
public ITempDataDictionaryFactory TempDataDictionaryFactory { get; set; }
|
public ITempDataDictionaryFactory TempDataDictionaryFactory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<PropertyInfo, object> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.GetStringAsync("http://localhost/Pages/Test");
|
var response = await Client.GetStringAsync("http://localhost/Pages/Test");
|
||||||
|
|
||||||
// Assert
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.AspNetCore.Razor.Evolution;
|
using Microsoft.AspNetCore.Razor.Evolution;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
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>();
|
||||||
|
razorProject.Setup(p => p.EnumerateItems("/"))
|
||||||
|
.Returns(new[]
|
||||||
|
{
|
||||||
|
GetProjectItem("/", "/Home.cshtml", $"@page {Environment.NewLine}"),
|
||||||
|
});
|
||||||
|
var provider = new PageActionDescriptorProvider(
|
||||||
|
razorProject.Object,
|
||||||
|
GetAccessor(options),
|
||||||
|
GetAccessor<RazorPagesOptions>());
|
||||||
|
var context = new ActionDescriptorProviderContext();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.OnProvidersExecuting(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var result = Assert.Single(context.Results);
|
||||||
|
var descriptor = Assert.IsType<PageActionDescriptor>(result);
|
||||||
|
Assert.Collection(
|
||||||
|
descriptor.FilterDescriptors,
|
||||||
|
filterDescriptor =>
|
||||||
|
{
|
||||||
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
|
Assert.IsType<SaveTempDataPropertyFilter>(filterDescriptor.Filter);
|
||||||
|
},
|
||||||
|
filterDescriptor =>
|
||||||
|
{
|
||||||
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
|
Assert.IsType<AutoValidateAntiforgeryTokenAttribute>(filterDescriptor.Filter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetDescriptors_AddsGlobalFilters()
|
public void GetDescriptors_AddsGlobalFilters()
|
||||||
{
|
{
|
||||||
|
|
@ -220,7 +259,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
// Assert
|
// Assert
|
||||||
var result = Assert.Single(context.Results);
|
var result = Assert.Single(context.Results);
|
||||||
var descriptor = Assert.IsType<PageActionDescriptor>(result);
|
var descriptor = Assert.IsType<PageActionDescriptor>(result);
|
||||||
Assert.Collection(descriptor.FilterDescriptors,
|
Assert.Collection(
|
||||||
|
descriptor.FilterDescriptors,
|
||||||
filterDescriptor =>
|
filterDescriptor =>
|
||||||
{
|
{
|
||||||
Assert.Equal(FilterScope.Global, filterDescriptor.Scope);
|
Assert.Equal(FilterScope.Global, filterDescriptor.Scope);
|
||||||
|
|
@ -230,6 +270,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
{
|
{
|
||||||
Assert.Equal(FilterScope.Global, filterDescriptor.Scope);
|
Assert.Equal(FilterScope.Global, filterDescriptor.Scope);
|
||||||
Assert.Same(filter2, filterDescriptor.Filter);
|
Assert.Same(filter2, filterDescriptor.Filter);
|
||||||
|
},
|
||||||
|
filterDescriptor =>
|
||||||
|
{
|
||||||
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
|
Assert.IsType<SaveTempDataPropertyFilter>(filterDescriptor.Filter);
|
||||||
|
},
|
||||||
|
filterDescriptor =>
|
||||||
|
{
|
||||||
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
|
Assert.IsType<AutoValidateAntiforgeryTokenAttribute>(filterDescriptor.Filter);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,6 +325,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
Assert.Same(globalFilter, filterDescriptor.Filter);
|
Assert.Same(globalFilter, filterDescriptor.Filter);
|
||||||
},
|
},
|
||||||
filterDescriptor =>
|
filterDescriptor =>
|
||||||
|
{
|
||||||
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
|
Assert.IsType<SaveTempDataPropertyFilter>(filterDescriptor.Filter);
|
||||||
|
},
|
||||||
|
filterDescriptor =>
|
||||||
|
{
|
||||||
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
|
Assert.IsType<AutoValidateAntiforgeryTokenAttribute>(filterDescriptor.Filter);
|
||||||
|
},
|
||||||
|
filterDescriptor =>
|
||||||
{
|
{
|
||||||
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||||
Assert.Same(localFilter, filterDescriptor.Filter);
|
Assert.Same(localFilter, filterDescriptor.Filter);
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
new TestOptionsManager<MvcOptions>(),
|
new TestOptionsManager<MvcOptions>(),
|
||||||
new TestOptionsManager<HtmlHelperOptions>(),
|
new TestOptionsManager<HtmlHelperOptions>(),
|
||||||
Mock.Of<IPageHandlerMethodSelector>(),
|
Mock.Of<IPageHandlerMethodSelector>(),
|
||||||
|
new TempDataPropertyProvider(),
|
||||||
razorProject,
|
razorProject,
|
||||||
new DiagnosticListener("Microsoft.AspNetCore"),
|
new DiagnosticListener("Microsoft.AspNetCore"),
|
||||||
NullLoggerFactory.Instance);
|
NullLoggerFactory.Instance);
|
||||||
|
|
|
||||||
|
|
@ -607,6 +607,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
|
||||||
var invoker = new PageActionInvoker(
|
var invoker = new PageActionInvoker(
|
||||||
selector,
|
selector,
|
||||||
|
new TempDataPropertyProvider(),
|
||||||
diagnosticSource,
|
diagnosticSource,
|
||||||
logger,
|
logger,
|
||||||
pageContext,
|
pageContext,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue