Fix [TempData] for PageModel's
This commit is contained in:
parent
1a8ac88da7
commit
59a3aade9b
|
|
@ -81,6 +81,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
// Action executors
|
||||
services.TryAddSingleton<PageResultExecutor>();
|
||||
services.TryAddSingleton<RedirectToPageResultExecutor>();
|
||||
|
||||
services.TryAddTransient<PageSaveTempDataPropertyFilter>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,28 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// </summary>
|
||||
public static class RazorPagesOptionsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the specified <paramref name="factory"/> to apply filters to all Razor Pages.
|
||||
/// </summary>
|
||||
/// <param name="options">The <see cref="RazorPagesOptions"/> to configure.</param>
|
||||
/// <param name="factory">The factory to create filters.</param>
|
||||
/// <returns></returns>
|
||||
public static RazorPagesOptions ConfigureFilter(this RazorPagesOptions options, Func<PageApplicationModel, IFilterMetadata> factory)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (factory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
|
||||
options.Conventions.Add(new FolderConvention("/", model => model.Filters.Add(factory(model))));
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the specified <paramref name="filter"/> to apply to all Razor Pages.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -346,10 +346,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
}
|
||||
|
||||
// This is a workaround for not yet having proper filter for Pages.
|
||||
SaveTempDataPropertyFilter propertyFilter = null;
|
||||
PageSaveTempDataPropertyFilter propertyFilter = null;
|
||||
for (var i = 0; i < _filters.Length; i++)
|
||||
{
|
||||
propertyFilter = _filters[i] as SaveTempDataPropertyFilter;
|
||||
propertyFilter = _filters[i] as PageSaveTempDataPropertyFilter;
|
||||
if (propertyFilter != null)
|
||||
{
|
||||
break;
|
||||
|
|
@ -358,7 +358,14 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
if (propertyFilter != null)
|
||||
{
|
||||
propertyFilter.Subject = _page;
|
||||
object subject = _page;
|
||||
|
||||
if (_model != null)
|
||||
{
|
||||
subject = _model;
|
||||
}
|
||||
|
||||
propertyFilter.Subject = subject;
|
||||
propertyFilter.ApplyTempDataChanges(_pageContext.HttpContext);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
}
|
||||
|
||||
// Support for [TempData] on properties
|
||||
options.ConfigureFilter(new SaveTempDataPropertyFilterFactory());
|
||||
options.ConfigureFilter(page => new PageSaveTempDataPropertyFilterFactory());
|
||||
|
||||
// Always require an antiforgery token on post
|
||||
options.ConfigureFilter(new AutoValidateAntiforgeryTokenAttribute());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IApplicationModelProvider, TempDataApplicationModelProvider>());
|
||||
services.TryAddSingleton<SaveTempDataFilter>();
|
||||
services.TryAddTransient<SaveTempDataPropertyFilter>();
|
||||
|
||||
|
||||
services.TryAddTransient<ControllerSaveTempDataPropertyFilter>();
|
||||
|
||||
// This does caching so it should stay singleton
|
||||
services.TryAddSingleton<ITempDataProvider, CookieTempDataProvider>();
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
// 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.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class SaveTempDataPropertyFilter : ISaveTempDataCallback, IActionFilter
|
||||
{
|
||||
private const string Prefix = "TempDataProperty-";
|
||||
private readonly ITempDataDictionaryFactory _factory;
|
||||
|
||||
public SaveTempDataPropertyFilter(ITempDataDictionaryFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
// Cannot be public as <c>PropertyHelper</c> is an internal shared source type
|
||||
internal IList<PropertyHelper> PropertyHelpers { get; set; }
|
||||
|
||||
public object Subject { get; set; }
|
||||
|
||||
public IDictionary<PropertyInfo, object> OriginalValues { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Puts the modified values of <see cref="Subject"/> into <paramref name="tempData"/>.
|
||||
/// </summary>
|
||||
/// <param name="tempData">The <see cref="ITempDataDictionary"/> to be updated.</param>
|
||||
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.Equals(originalValue))
|
||||
{
|
||||
tempData[Prefix + property.Name] = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies values from TempData from <paramref name="httpContext"/> to the <see cref="Subject"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> used to find TempData.</param>
|
||||
public void ApplyTempDataChanges(HttpContext httpContext)
|
||||
{
|
||||
if (Subject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Subject));
|
||||
}
|
||||
|
||||
var tempData = _factory.GetTempData(httpContext);
|
||||
|
||||
if (OriginalValues == null)
|
||||
{
|
||||
OriginalValues = new Dictionary<PropertyInfo, object>();
|
||||
}
|
||||
|
||||
SetPropertyVaules(tempData, Subject);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
Subject = context.Controller;
|
||||
var tempData = _factory.GetTempData(context.HttpContext);
|
||||
|
||||
OriginalValues = new Dictionary<PropertyInfo, object>();
|
||||
|
||||
SetPropertyVaules(tempData, Subject);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
private void SetPropertyVaules(ITempDataDictionary tempData, object subject)
|
||||
{
|
||||
if (PropertyHelpers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < PropertyHelpers.Count; i++)
|
||||
{
|
||||
var property = PropertyHelpers[i];
|
||||
var value = tempData[Prefix + property.Name];
|
||||
|
||||
OriginalValues[property.Property] = value;
|
||||
|
||||
var propertyTypeInfo = property.Property.PropertyType.GetTypeInfo();
|
||||
|
||||
var isReferenceTypeOrNullable = !propertyTypeInfo.IsValueType || Nullable.GetUnderlyingType(property.GetType()) != null;
|
||||
if (value != null || isReferenceTypeOrNullable)
|
||||
{
|
||||
property.SetValue(subject, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// 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 class ControllerSaveTempDataPropertyFilter : SaveTempDataPropertyFilterBase, IActionFilter
|
||||
{
|
||||
public ControllerSaveTempDataPropertyFilter(ITempDataDictionaryFactory factory)
|
||||
: base(factory)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
Subject = context.Controller;
|
||||
var tempData = _factory.GetTempData(context.HttpContext);
|
||||
|
||||
SetPropertyVaules(tempData, Subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5,14 +5,12 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class SaveTempDataPropertyFilterFactory : IFilterFactory
|
||||
public class ControllerSaveTempDataPropertyFilterFactory : IFilterFactory
|
||||
{
|
||||
// Cannot be public as <c>PropertyHelper</c> is an internal shared source type
|
||||
internal IList<PropertyHelper> TempDataProperties { get; set; }
|
||||
public IList<TempDataProperty> TempDataProperties { get; set; }
|
||||
|
||||
public bool IsReusable => false;
|
||||
|
||||
|
|
@ -23,8 +21,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
var service = serviceProvider.GetRequiredService<SaveTempDataPropertyFilter>();
|
||||
service.PropertyHelpers = TempDataProperties;
|
||||
var service = serviceProvider.GetRequiredService<ControllerSaveTempDataPropertyFilter>();
|
||||
service.TempDataProperties = TempDataProperties;
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class PageSaveTempDataPropertyFilter : SaveTempDataPropertyFilterBase
|
||||
{
|
||||
public PageSaveTempDataPropertyFilter(ITempDataDictionaryFactory factory)
|
||||
: base(factory)
|
||||
{
|
||||
}
|
||||
|
||||
public PageSaveTempDataPropertyFilterFactory FilterFactory { get; set; }
|
||||
|
||||
public override object Subject {
|
||||
get => base.Subject;
|
||||
set
|
||||
{
|
||||
base.Subject = value;
|
||||
SetTempDataProperties(value.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTempDataProperties(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
if (FilterFactory == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(FilterFactory),
|
||||
typeof(PageSaveTempDataPropertyFilter).Name));
|
||||
}
|
||||
|
||||
TempDataProperties = FilterFactory.GetTempDataProperties(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies values from TempData from <paramref name="httpContext"/> to the
|
||||
/// <see cref="SaveTempDataPropertyFilterBase.Subject"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> used to find TempData.</param>
|
||||
public void ApplyTempDataChanges(HttpContext httpContext)
|
||||
{
|
||||
if (Subject == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(Subject),
|
||||
typeof(PageSaveTempDataPropertyFilter).Name));
|
||||
}
|
||||
|
||||
var tempData = _factory.GetTempData(httpContext);
|
||||
|
||||
SetPropertyVaules(tempData, Subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// 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.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class PageSaveTempDataPropertyFilterFactory : IFilterFactory
|
||||
{
|
||||
public IList<TempDataProperty> TempDataProperties { get; set; }
|
||||
|
||||
public bool IsReusable => false;
|
||||
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
var service = serviceProvider.GetRequiredService<PageSaveTempDataPropertyFilter>();
|
||||
service.FilterFactory = this;
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
public IList<TempDataProperty> GetTempDataProperties(Type modelType)
|
||||
{
|
||||
// TempDataProperties are stored here as a cache for the filter. But in pages by the time we know the type
|
||||
// of our model we no longer have access to the factory, so we store the factory on the filter so it can
|
||||
// call this method to populate its TempDataProperties.
|
||||
if (TempDataProperties == null)
|
||||
{
|
||||
TempDataProperties = SaveTempDataPropertyFilterBase.GetTempDataProperties(modelType);
|
||||
}
|
||||
|
||||
return TempDataProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
// 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.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public abstract class SaveTempDataPropertyFilterBase : ISaveTempDataCallback
|
||||
{
|
||||
protected const string Prefix = "TempDataProperty-";
|
||||
|
||||
protected readonly ITempDataDictionaryFactory _factory;
|
||||
|
||||
/// <summary>
|
||||
/// Describes the temp data properties which exist on <see cref="Subject"/>
|
||||
/// </summary>
|
||||
public IList<TempDataProperty> TempDataProperties { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="object"/> which has the temp data properties.
|
||||
/// </summary>
|
||||
public virtual object Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the values which originally existed in temp data.
|
||||
/// </summary>
|
||||
public IDictionary<PropertyInfo, object> OriginalValues { get; } = new Dictionary<PropertyInfo, object>();
|
||||
|
||||
public SaveTempDataPropertyFilterBase(ITempDataDictionaryFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts the modified values of <see cref="Subject"/> into <paramref name="tempData"/>.
|
||||
/// </summary>
|
||||
/// <param name="tempData">The <see cref="ITempDataDictionary"/> to be updated.</param>
|
||||
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.Equals(originalValue))
|
||||
{
|
||||
tempData[Prefix + property.Name] = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IList<TempDataProperty> GetTempDataProperties(Type type)
|
||||
{
|
||||
List<TempDataProperty> results = null;
|
||||
|
||||
var propertyHelpers = PropertyHelper.GetVisibleProperties(type: type);
|
||||
|
||||
for (var i = 0; i < propertyHelpers.Length; i++)
|
||||
{
|
||||
var propertyHelper = propertyHelpers[i];
|
||||
if (propertyHelper.Property.IsDefined(typeof(TempDataAttribute)))
|
||||
{
|
||||
ValidateProperty(propertyHelper);
|
||||
if (results == null)
|
||||
{
|
||||
results = new List<TempDataProperty>();
|
||||
}
|
||||
|
||||
results.Add(new TempDataProperty(
|
||||
propertyHelper.Property,
|
||||
propertyHelper.GetValue,
|
||||
propertyHelper.SetValue));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void ValidateProperty(PropertyHelper propertyHelper)
|
||||
{
|
||||
var property = propertyHelper.Property;
|
||||
if (!(property.SetMethod != null &&
|
||||
property.SetMethod.IsPublic &&
|
||||
property.GetMethod != null &&
|
||||
property.GetMethod.IsPublic))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatTempDataProperties_PublicGetterSetter(property.DeclaringType.FullName, property.Name, nameof(TempDataAttribute)));
|
||||
}
|
||||
|
||||
if (!(property.PropertyType.GetTypeInfo().IsPrimitive || property.PropertyType == typeof(string)))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatTempDataProperties_PrimitiveTypeOrString(property.DeclaringType.FullName, property.Name, nameof(TempDataAttribute)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the values of the properties of <paramref name="subject"/> from <paramref name="tempData"/>.
|
||||
/// </summary>
|
||||
/// <param name="tempData">The <see cref="ITempDataDictionary"/> with the data to set on <paramref name="subject"/>.</param>
|
||||
/// <param name="subject">The <see cref="object"/> which will have it's properties set.</param>
|
||||
protected void SetPropertyVaules(ITempDataDictionary tempData, object subject)
|
||||
{
|
||||
if (TempDataProperties == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < TempDataProperties.Count; i++)
|
||||
{
|
||||
var property = TempDataProperties[i];
|
||||
var value = tempData[Prefix + property.PropertyInfo.Name];
|
||||
|
||||
OriginalValues[property.PropertyInfo] = value;
|
||||
|
||||
var propertyTypeInfo = property.PropertyInfo.PropertyType.GetTypeInfo();
|
||||
|
||||
var isReferenceTypeOrNullable = !propertyTypeInfo.IsValueType || Nullable.GetUnderlyingType(property.GetType()) != null;
|
||||
if (value != null || isReferenceTypeOrNullable)
|
||||
{
|
||||
property.SetValue(subject, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// 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.Reflection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public struct TempDataProperty
|
||||
{
|
||||
private Func<object, object> _getter;
|
||||
|
||||
private Action<object, object> _setter;
|
||||
|
||||
public TempDataProperty(PropertyInfo propertyInfo, Func<object, object> getter, Action<object, object> setter)
|
||||
{
|
||||
PropertyInfo = propertyInfo;
|
||||
_getter = getter;
|
||||
_setter = setter;
|
||||
}
|
||||
|
||||
public PropertyInfo PropertyInfo { get; }
|
||||
|
||||
public object GetValue(object obj)
|
||||
{
|
||||
return _getter(obj);
|
||||
}
|
||||
|
||||
public void SetValue(object obj, object value)
|
||||
{
|
||||
_setter(obj, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
|
|
@ -31,50 +28,20 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
|
||||
foreach (var controllerModel in context.Result.Controllers)
|
||||
{
|
||||
SaveTempDataPropertyFilterFactory factory = null;
|
||||
var propertyHelpers = PropertyHelper.GetVisibleProperties(type: controllerModel.ControllerType.AsType());
|
||||
for (var i = 0; i < propertyHelpers.Length; i++)
|
||||
|
||||
var modelType = controllerModel.ControllerType.AsType();
|
||||
var tempDataProperties = SaveTempDataPropertyFilterBase.GetTempDataProperties(modelType);
|
||||
|
||||
if (tempDataProperties != null)
|
||||
{
|
||||
var propertyHelper = propertyHelpers[i];
|
||||
if (propertyHelper.Property.IsDefined(typeof(TempDataAttribute)))
|
||||
var factory = new ControllerSaveTempDataPropertyFilterFactory()
|
||||
{
|
||||
ValidateProperty(propertyHelper);
|
||||
if (factory == null)
|
||||
{
|
||||
factory = new SaveTempDataPropertyFilterFactory()
|
||||
{
|
||||
TempDataProperties = new List<PropertyHelper>()
|
||||
};
|
||||
}
|
||||
TempDataProperties = tempDataProperties
|
||||
};
|
||||
|
||||
factory.TempDataProperties.Add(propertyHelper);
|
||||
}
|
||||
}
|
||||
|
||||
if (factory != null)
|
||||
{
|
||||
controllerModel.Filters.Add(factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateProperty(PropertyHelper propertyHelper)
|
||||
{
|
||||
var property = propertyHelper.Property;
|
||||
if (!(property.SetMethod != null &&
|
||||
property.SetMethod.IsPublic &&
|
||||
property.GetMethod != null &&
|
||||
property.GetMethod.IsPublic))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatTempDataProperties_PublicGetterSetter(property.DeclaringType.FullName, property.Name, nameof(TempDataAttribute)));
|
||||
}
|
||||
|
||||
if (!(property.PropertyType.GetTypeInfo().IsPrimitive || property.PropertyType == typeof(string)))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatTempDataProperties_PrimitiveTypeOrString(property.DeclaringType.FullName, property.Name, nameof(TempDataAttribute)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
{
|
||||
// Arrange
|
||||
var routeRequest = new HttpRequestMessage(HttpMethod.Get, "http://localhost/RouteData/pizza");
|
||||
|
||||
|
||||
// Act
|
||||
var routeResponse = await Client.SendAsync(routeRequest);
|
||||
|
||||
|
|
@ -413,6 +413,69 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal("Hi2", content.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TempData_TempDataPropertyOnPageModel_IsPopulatedFromTempData()
|
||||
{
|
||||
// Arrange 1
|
||||
var url = "http://localhost/TempData/SetMessageAndRedirect";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
|
||||
// Act 1
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert 1
|
||||
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||
|
||||
// Act 2
|
||||
request = new HttpRequestMessage(HttpMethod.Get, response.Headers.Location);
|
||||
request.Headers.Add("Cookie", GetCookie(response));
|
||||
response = await Client.SendAsync(request);
|
||||
|
||||
// Assert 2
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.StartsWith("Message: Secret Message", content.Trim());
|
||||
Assert.EndsWith("TempData: Secret Message", content.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TempData_TempDataPropertyOnPageModel_PopulatesTempData()
|
||||
{
|
||||
// Arrange 1
|
||||
var getRequest = new HttpRequestMessage(HttpMethod.Get, "http://localhost/TempData/TempDataPageModelProperty");
|
||||
var getResponse = await Client.SendAsync(getRequest);
|
||||
var getResponseBody = await getResponse.Content.ReadAsStringAsync();
|
||||
var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(getResponseBody, "/TempData/TempDataPageModelProperty");
|
||||
var cookie = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
|
||||
|
||||
var url = "http://localhost/TempData/TempDataPageModelProperty";
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, url);
|
||||
request.Headers.Add("Cookie", cookie.Key + "=" + cookie.Value);
|
||||
request.Headers.Add("RequestVerificationToken", formToken);
|
||||
|
||||
// Act 1
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert 1
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.StartsWith("Message: Secret post", content.Trim());
|
||||
Assert.EndsWith("TempData:", content.Trim());
|
||||
|
||||
// Arrange 2
|
||||
request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/TempData/TempDataPageModelProperty");
|
||||
request.Headers.Add("Cookie", GetCookie(response));
|
||||
|
||||
// Act 2
|
||||
response = await Client.SendAsync(request);
|
||||
|
||||
// Assert 2
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
content = await response.Content.ReadAsStringAsync();
|
||||
Assert.StartsWith("Message: Secret post", content.Trim());
|
||||
Assert.EndsWith("TempData: Secret post", content.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthorizePage_AddsAuthorizationForSpecificPages()
|
||||
{
|
||||
|
|
@ -432,7 +495,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
{
|
||||
// Arrange
|
||||
var url = "/Pages/Admin/Login";
|
||||
|
||||
|
||||
// Act
|
||||
var response = await Client.GetAsync(url);
|
||||
|
||||
|
|
@ -677,7 +740,7 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP
|
|||
Assert.Equal(expected, response.Headers.Location.ToString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task RedirectToSelfWorks()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
filterDescriptor =>
|
||||
{
|
||||
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||
Assert.IsType<SaveTempDataPropertyFilterFactory>(filterDescriptor.Filter);
|
||||
Assert.IsType<PageSaveTempDataPropertyFilterFactory>(filterDescriptor.Filter);
|
||||
},
|
||||
filterDescriptor =>
|
||||
{
|
||||
|
|
@ -343,7 +343,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
filterDescriptor =>
|
||||
{
|
||||
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||
Assert.IsType<SaveTempDataPropertyFilterFactory>(filterDescriptor.Filter);
|
||||
Assert.IsType<PageSaveTempDataPropertyFilterFactory>(filterDescriptor.Filter);
|
||||
},
|
||||
filterDescriptor =>
|
||||
{
|
||||
|
|
@ -396,7 +396,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
filterDescriptor =>
|
||||
{
|
||||
Assert.Equal(FilterScope.Action, filterDescriptor.Scope);
|
||||
Assert.IsType<SaveTempDataPropertyFilterFactory>(filterDescriptor.Filter);
|
||||
Assert.IsType<PageSaveTempDataPropertyFilterFactory>(filterDescriptor.Filter);
|
||||
},
|
||||
filterDescriptor =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
// Assert
|
||||
Assert.Collection(applicationModel.Filters,
|
||||
filter => Assert.IsType<SaveTempDataPropertyFilterFactory>(filter),
|
||||
filter => Assert.IsType<PageSaveTempDataPropertyFilterFactory>(filter),
|
||||
filter => Assert.IsType<AutoValidateAntiforgeryTokenAttribute>(filter));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
// 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.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class ControllerSaveTempDataPropertyFilterFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public void CreateInstance_CreatesFilter()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new ControllerSaveTempDataPropertyFilterFactory();
|
||||
var propertyInfo = typeof(StringController).GetProperty("StringProp");
|
||||
|
||||
factory.TempDataProperties = new List<TempDataProperty>()
|
||||
{
|
||||
new TempDataProperty(propertyInfo, null, null)
|
||||
};
|
||||
|
||||
// Act
|
||||
var filter = factory.CreateInstance(CreateServiceProvider());
|
||||
|
||||
// Assert
|
||||
var controllerFilter = Assert.IsType<ControllerSaveTempDataPropertyFilter>(filter);
|
||||
Assert.Collection(controllerFilter.TempDataProperties,
|
||||
property => Assert.Equal("StringProp", property.PropertyInfo.Name));
|
||||
}
|
||||
|
||||
private ServiceProvider CreateServiceProvider()
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
||||
serviceCollection.AddSingleton(Mock.Of<ITempDataProvider>());
|
||||
serviceCollection.AddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
|
||||
serviceCollection.AddTransient<ControllerSaveTempDataPropertyFilter>();
|
||||
|
||||
return serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
private class StringController
|
||||
{
|
||||
public string StringProp { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,21 +2,19 @@
|
|||
// 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;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class SaveTempDataPropertyFilterTest
|
||||
public class ControllerSaveTempDataPropertyFilterTest
|
||||
{
|
||||
[Fact]
|
||||
public void SaveTempDataPropertyFilter_PopulatesTempDataWithValuesFromControllerProperty()
|
||||
public void PopulatesTempDataWithValuesFromControllerProperty()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
|
@ -25,11 +23,20 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
["TempDataProperty-Test"] = "FirstValue"
|
||||
};
|
||||
|
||||
var filter = CreateSaveTempDataPropertyFilter(httpContext, tempData);
|
||||
var filter = CreateControllerSaveTempDataPropertyFilter(httpContext, tempData);
|
||||
|
||||
var controller = new TestController();
|
||||
|
||||
filter.PropertyHelpers = BuildPropertyHelpers<TestController>();
|
||||
var controllerType = controller.GetType();
|
||||
var testProp = controllerType.GetProperty(nameof(TestController.Test));
|
||||
var test2Prop = controllerType.GetProperty(nameof(TestController.Test2));
|
||||
|
||||
filter.TempDataProperties = new List<TempDataProperty>
|
||||
{
|
||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
||||
};
|
||||
|
||||
var context = new ActionExecutingContext(
|
||||
new ActionContext
|
||||
{
|
||||
|
|
@ -53,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void SaveTempDataPropertyFilter_ReadsTempDataFromTempDataDictionary()
|
||||
public void ReadsTempDataFromTempDataDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
|
@ -62,10 +69,18 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
["TempDataProperty-Test"] = "FirstValue"
|
||||
};
|
||||
|
||||
var filter = CreateSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
var filter = CreateControllerSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
var controller = new TestController();
|
||||
|
||||
filter.PropertyHelpers = BuildPropertyHelpers<TestController>();
|
||||
var controllerType = controller.GetType();
|
||||
var testProp = controllerType.GetProperty(nameof(TestController.Test));
|
||||
var test2Prop = controllerType.GetProperty(nameof(TestController.Test2));
|
||||
|
||||
filter.TempDataProperties = new List<TempDataProperty>
|
||||
{
|
||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
||||
};
|
||||
|
||||
var context = new ActionExecutingContext(
|
||||
new ActionContext
|
||||
|
|
@ -87,53 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
Assert.Equal(0, controller.Test2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyTempDataChanges_SetsPropertyValue()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||
{
|
||||
{ "TempDataProperty-Test", "Value" }
|
||||
};
|
||||
tempData.Save();
|
||||
|
||||
var controller = new TestControllerStrings()
|
||||
{
|
||||
TempData = tempData,
|
||||
};
|
||||
|
||||
var provider = CreateSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
provider.Subject = controller;
|
||||
provider.PropertyHelpers = BuildPropertyHelpers<TestControllerStrings>();
|
||||
|
||||
// Act
|
||||
provider.ApplyTempDataChanges(httpContext);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Value", controller.Test);
|
||||
Assert.Null(controller.Test2);
|
||||
}
|
||||
|
||||
private IList<PropertyHelper> BuildPropertyHelpers<TSubject>()
|
||||
{
|
||||
var subjectType = typeof(TSubject);
|
||||
|
||||
var properties = subjectType.GetProperties(
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
||||
|
||||
var result = new List<PropertyHelper>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
result.Add(new PropertyHelper(property));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private SaveTempDataPropertyFilter CreateSaveTempDataPropertyFilter(
|
||||
private ControllerSaveTempDataPropertyFilter CreateControllerSaveTempDataPropertyFilter(
|
||||
HttpContext httpContext,
|
||||
TempDataDictionary tempData)
|
||||
{
|
||||
|
|
@ -141,16 +110,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
factory.Setup(f => f.GetTempData(httpContext))
|
||||
.Returns(tempData);
|
||||
|
||||
return new SaveTempDataPropertyFilter(factory.Object);
|
||||
}
|
||||
|
||||
public class TestControllerStrings : Controller
|
||||
{
|
||||
[TempData]
|
||||
public string Test { get; set; }
|
||||
|
||||
[TempData]
|
||||
public string Test2 { get; set; }
|
||||
return new ControllerSaveTempDataPropertyFilter(factory.Object);
|
||||
}
|
||||
|
||||
public class TestController : Controller
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class PageSaveTempDataPropertyFilterFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public void CreatesInstanceWithProperties()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new PageSaveTempDataPropertyFilterFactory();
|
||||
|
||||
var serviceProvider = CreateServiceProvider();
|
||||
|
||||
// Act
|
||||
var filter = factory.CreateInstance(serviceProvider);
|
||||
|
||||
// Assert
|
||||
var pageFilter = Assert.IsType<PageSaveTempDataPropertyFilter>(filter);
|
||||
Assert.Same(factory, pageFilter.FilterFactory);
|
||||
}
|
||||
|
||||
private ServiceProvider CreateServiceProvider()
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
||||
serviceCollection.AddSingleton(Mock.Of<ITempDataProvider>());
|
||||
serviceCollection.AddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
|
||||
serviceCollection.AddTransient<PageSaveTempDataPropertyFilter>();
|
||||
|
||||
return serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
// 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.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class PageSaveTempDataPropertyFilterTest
|
||||
{
|
||||
[Fact]
|
||||
public void OnTempDataSaving_PopulatesTempDataWithValuesFromPageProperty()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||
{
|
||||
{ "TempDataProperty-Test", "TestString" }
|
||||
};
|
||||
tempData.Save();
|
||||
|
||||
var page = new TestPageString()
|
||||
{
|
||||
Test = "TestString",
|
||||
ViewContext = CreateViewContext(httpContext, tempData)
|
||||
};
|
||||
|
||||
var provider = CreatePageSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
provider.Subject = page;
|
||||
|
||||
var pageType = page.GetType();
|
||||
|
||||
var testProp = pageType.GetProperty(nameof(TestPageString.Test));
|
||||
var test2Prop = pageType.GetProperty(nameof(TestPageString.Test2));
|
||||
|
||||
provider.TempDataProperties = new List<TempDataProperty>{
|
||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
||||
};
|
||||
|
||||
// Act
|
||||
provider.OnTempDataSaving(tempData);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("TestString", page.Test);
|
||||
Assert.Equal("TestString", page.TempData["TempDataProperty-Test"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetSubject_NullFilterFactory_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
|
||||
tempData.Save();
|
||||
|
||||
var page = new TestPageString()
|
||||
{
|
||||
ViewContext = CreateViewContext(httpContext, tempData)
|
||||
};
|
||||
|
||||
var provider = CreatePageSaveTempDataPropertyFilter(httpContext, tempData: tempData, filterFactory: false);
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => provider.Subject = page);
|
||||
Assert.Contains("FilterFactory", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetSubject_ModifiesFactoryAndFilter()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
|
||||
tempData.Save();
|
||||
|
||||
var page = new TestPageString()
|
||||
{
|
||||
Test = "TestString",
|
||||
ViewContext = CreateViewContext(httpContext, tempData)
|
||||
};
|
||||
|
||||
var provider = CreatePageSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
provider.FilterFactory = new PageSaveTempDataPropertyFilterFactory();
|
||||
|
||||
// Act
|
||||
provider.Subject = page;
|
||||
|
||||
// Assert
|
||||
Assert.Collection(provider.TempDataProperties,
|
||||
property => Assert.Equal("Test", property.PropertyInfo.Name),
|
||||
property => Assert.Equal("Test2", property.PropertyInfo.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyTempDataChanges_ToPageModel_SetsPropertyValue()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||
{
|
||||
{ "TempDataProperty-Test", "Value" }
|
||||
};
|
||||
tempData.Save();
|
||||
|
||||
var page = new TestPageString()
|
||||
{
|
||||
ViewContext = CreateViewContext(httpContext, tempData)
|
||||
};
|
||||
|
||||
var provider = CreatePageSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
provider.Subject = page;
|
||||
|
||||
var pageType = typeof(TestPageString);
|
||||
var testProp = pageType.GetProperty("Test");
|
||||
var test2Prop = pageType.GetProperty("Test2");
|
||||
|
||||
provider.TempDataProperties = new List<TempDataProperty> {
|
||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
||||
};
|
||||
|
||||
// Act
|
||||
provider.ApplyTempDataChanges(httpContext);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Value", page.Test);
|
||||
Assert.Null(page.Test2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyTempDataChanges_ToPage_SetsPropertyValue()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||
{
|
||||
{ "TempDataProperty-Test", "Value" }
|
||||
};
|
||||
tempData.Save();
|
||||
|
||||
var page = new TestPageString()
|
||||
{
|
||||
ViewContext = CreateViewContext(httpContext, tempData)
|
||||
};
|
||||
|
||||
var provider = CreatePageSaveTempDataPropertyFilter(httpContext, tempData: tempData);
|
||||
provider.Subject = page;
|
||||
|
||||
var pageType = page.GetType();
|
||||
|
||||
var testProp = pageType.GetProperty(nameof(TestPageString.Test));
|
||||
var test2Prop = pageType.GetProperty(nameof(TestPageString.Test2));
|
||||
|
||||
provider.TempDataProperties = new List<TempDataProperty> {
|
||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
||||
};
|
||||
|
||||
// Act
|
||||
provider.ApplyTempDataChanges(httpContext);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Value", page.Test);
|
||||
Assert.Null(page.Test2);
|
||||
}
|
||||
|
||||
private static PageContext CreateViewContext(HttpContext httpContext, ITempDataDictionary tempData)
|
||||
{
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
|
||||
var viewContext = new PageContext(
|
||||
actionContext,
|
||||
viewData,
|
||||
tempData,
|
||||
new HtmlHelperOptions());
|
||||
|
||||
return viewContext;
|
||||
}
|
||||
|
||||
private PageSaveTempDataPropertyFilter CreatePageSaveTempDataPropertyFilter(
|
||||
HttpContext httpContext,
|
||||
TempDataDictionary tempData,
|
||||
bool filterFactory = true)
|
||||
{
|
||||
var factory = new Mock<ITempDataDictionaryFactory>();
|
||||
factory.Setup(f => f.GetTempData(httpContext))
|
||||
.Returns(tempData);
|
||||
|
||||
var propertyFilter = new PageSaveTempDataPropertyFilter(factory.Object);
|
||||
|
||||
if (filterFactory)
|
||||
{
|
||||
propertyFilter.FilterFactory = new Mock<PageSaveTempDataPropertyFilterFactory>().Object;
|
||||
}
|
||||
|
||||
return propertyFilter;
|
||||
}
|
||||
|
||||
public class TestPageString : Page
|
||||
{
|
||||
[TempData]
|
||||
public string Test { get; set; }
|
||||
|
||||
[TempData]
|
||||
public string Test2 { get; set; }
|
||||
|
||||
public override Task ExecuteAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class TestPageStringWithModel : Page
|
||||
{
|
||||
public PageModel TestPageModelWithString { get; set; }
|
||||
|
||||
public override Task ExecuteAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class TestPageModelWithString : PageModel
|
||||
{
|
||||
[TempData]
|
||||
public string Test { get; set; }
|
||||
|
||||
[TempData]
|
||||
public string Test2 { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
|
||||
// Assert
|
||||
var controller = Assert.Single(context.Result.Controllers);
|
||||
Assert.Single(controller.Filters, f => f is SaveTempDataPropertyFilterFactory);
|
||||
Assert.Single(controller.Filters, f => f is ControllerSaveTempDataPropertyFilterFactory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -46,14 +46,14 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
// Act
|
||||
provider.OnProvidersExecuting(context);
|
||||
var controller = context.Result.Controllers.SingleOrDefault();
|
||||
var filter = controller.Filters.OfType<SaveTempDataPropertyFilterFactory>();
|
||||
var filter = controller.Filters.OfType<ControllerSaveTempDataPropertyFilterFactory>();
|
||||
var saveTempDataPropertyFilterFactory = filter.SingleOrDefault();
|
||||
var expected = typeof(TestController_OneTempDataProperty).GetProperty(nameof(TestController_OneTempDataProperty.Test2));
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(saveTempDataPropertyFilterFactory);
|
||||
var tempDataPropertyHelper = Assert.Single(saveTempDataPropertyFilterFactory.TempDataProperties);
|
||||
Assert.Same(expected, tempDataPropertyHelper.Property);
|
||||
Assert.Same(expected, tempDataPropertyHelper.PropertyInfo);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
@page
|
||||
|
||||
@functions
|
||||
{
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
TempData["TempDataProperty-Message"] = "Secret Message";
|
||||
return Redirect("~/TempData/TempDataPageModelProperty");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace RazorPagesWebSite.TempData
|
||||
{
|
||||
public class TempDataPageModel : PageModel
|
||||
{
|
||||
[TempData]
|
||||
public string Message { get; set; }
|
||||
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult OnPost()
|
||||
{
|
||||
Message = "Secret post";
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
@page
|
||||
@model RazorPagesWebSite.TempData.TempDataPageModel
|
||||
|
||||
Message: @Model.Message
|
||||
@using (Html.BeginForm())
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
}
|
||||
TempData: @TempData["TempDataProperty-Message"]
|
||||
Loading…
Reference in New Issue