diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs index 406d44661c..1a2c4e1cae 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs @@ -81,6 +81,8 @@ namespace Microsoft.Extensions.DependencyInjection // Action executors services.TryAddSingleton(); services.TryAddSingleton(); + + services.TryAddTransient(); } } } diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs index fe6b98006b..a14df1b6a8 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs @@ -14,6 +14,28 @@ namespace Microsoft.Extensions.DependencyInjection /// public static class RazorPagesOptionsExtensions { + /// + /// Configures the specified to apply filters to all Razor Pages. + /// + /// The to configure. + /// The factory to create filters. + /// + public static RazorPagesOptions ConfigureFilter(this RazorPagesOptions options, Func 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; + } + /// /// Configures the specified to apply to all Razor Pages. /// diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs index 3099ec48e9..db1d9f64d5 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs @@ -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); } diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs index 134075a2e4..929e2bc98a 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs @@ -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()); } diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index 232bbe532e..5cf9d730d5 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -201,7 +201,9 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddEnumerable( ServiceDescriptor.Transient()); services.TryAddSingleton(); - services.TryAddTransient(); + + + services.TryAddTransient(); // This does caching so it should stay singleton services.TryAddSingleton(); diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs deleted file mode 100644 index 62c419e207..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter.cs +++ /dev/null @@ -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 PropertyHelper is an internal shared source type - internal IList PropertyHelpers { get; set; } - - public object Subject { get; set; } - - public IDictionary OriginalValues { get; set; } - - /// - /// Puts the modified values of into . - /// - /// The to be updated. - 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; - } - } - } - } - - /// - /// Applies values from TempData from to the . - /// - /// The used to find TempData. - public void ApplyTempDataChanges(HttpContext httpContext) - { - if (Subject == null) - { - throw new ArgumentNullException(nameof(Subject)); - } - - var tempData = _factory.GetTempData(httpContext); - - if (OriginalValues == null) - { - OriginalValues = new Dictionary(); - } - - SetPropertyVaules(tempData, Subject); - } - - /// - public void OnActionExecuting(ActionExecutingContext context) - { - Subject = context.Controller; - var tempData = _factory.GetTempData(context.HttpContext); - - OriginalValues = new Dictionary(); - - SetPropertyVaules(tempData, Subject); - } - - /// - 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); - } - } - } - } -} - diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/ControllerSaveTempDataPropertyFilter.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/ControllerSaveTempDataPropertyFilter.cs new file mode 100644 index 0000000000..ff35fac0f4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/ControllerSaveTempDataPropertyFilter.cs @@ -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) + { + } + + /// + public void OnActionExecuting(ActionExecutingContext context) + { + Subject = context.Controller; + var tempData = _factory.GetTempData(context.HttpContext); + + SetPropertyVaules(tempData, Subject); + } + } +} + diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilterFactory.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/ControllerSaveTempDataPropertyFilterFactory.cs similarity index 63% rename from src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilterFactory.cs rename to src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/ControllerSaveTempDataPropertyFilterFactory.cs index 27286dcb91..110c01eb03 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilterFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/ControllerSaveTempDataPropertyFilterFactory.cs @@ -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 PropertyHelper is an internal shared source type - internal IList TempDataProperties { get; set; } + public IList 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(); - service.PropertyHelpers = TempDataProperties; + var service = serviceProvider.GetRequiredService(); + service.TempDataProperties = TempDataProperties; return service; } } diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/PageSaveTempDataPropertyFilter.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/PageSaveTempDataPropertyFilter.cs new file mode 100644 index 0000000000..636cee7ceb --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/PageSaveTempDataPropertyFilter.cs @@ -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); + } + + /// + /// Applies values from TempData from to the + /// . + /// + /// The used to find TempData. + 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); + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/PageSaveTempDataPropertyFilterFactory.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/PageSaveTempDataPropertyFilterFactory.cs new file mode 100644 index 0000000000..50f1e053b6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/PageSaveTempDataPropertyFilterFactory.cs @@ -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 TempDataProperties { get; set; } + + public bool IsReusable => false; + + public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) + { + if (serviceProvider == null) + { + throw new ArgumentNullException(nameof(serviceProvider)); + } + + var service = serviceProvider.GetRequiredService(); + service.FilterFactory = this; + + return service; + } + + public IList 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; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/SaveTempDataPropertyFilterBase.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/SaveTempDataPropertyFilterBase.cs new file mode 100644 index 0000000000..03f4e633b7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/SaveTempDataPropertyFilterBase.cs @@ -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; + + /// + /// Describes the temp data properties which exist on + /// + public IList TempDataProperties { get; set; } + + /// + /// The which has the temp data properties. + /// + public virtual object Subject { get; set; } + + /// + /// Tracks the values which originally existed in temp data. + /// + public IDictionary OriginalValues { get; } = new Dictionary(); + + public SaveTempDataPropertyFilterBase(ITempDataDictionaryFactory factory) + { + _factory = factory; + } + + /// + /// Puts the modified values of into . + /// + /// The to be updated. + 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 GetTempDataProperties(Type type) + { + List 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(); + } + + 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))); + } + } + + /// + /// Sets the values of the properties of from . + /// + /// The with the data to set on . + /// The which will have it's properties set. + 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); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/TempDataProperty.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/TempDataProperty.cs new file mode 100644 index 0000000000..160172c823 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/SaveTempDataPropertyFilter/TempDataProperty.cs @@ -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 _getter; + + private Action _setter; + + public TempDataProperty(PropertyInfo propertyInfo, Func getter, Action 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); + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/TempDataApplicationModelProvider.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/TempDataApplicationModelProvider.cs index 240d88fc3f..a1c4e4ec99 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/TempDataApplicationModelProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/TempDataApplicationModelProvider.cs @@ -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() - }; - } + 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))); - } - } } } diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs index 76c8012244..507b872b17 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs @@ -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() { diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs index cee7385b1f..79ad7dff74 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs @@ -292,7 +292,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure filterDescriptor => { Assert.Equal(FilterScope.Action, filterDescriptor.Scope); - Assert.IsType(filterDescriptor.Filter); + Assert.IsType(filterDescriptor.Filter); }, filterDescriptor => { @@ -343,7 +343,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure filterDescriptor => { Assert.Equal(FilterScope.Action, filterDescriptor.Scope); - Assert.IsType(filterDescriptor.Filter); + Assert.IsType(filterDescriptor.Filter); }, filterDescriptor => { @@ -396,7 +396,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure filterDescriptor => { Assert.Equal(FilterScope.Action, filterDescriptor.Scope); - Assert.IsType(filterDescriptor.Filter); + Assert.IsType(filterDescriptor.Filter); }, filterDescriptor => { diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs index 0d9c219f71..95a4cf6aa2 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal // Assert Assert.Collection(applicationModel.Filters, - filter => Assert.IsType(filter), + filter => Assert.IsType(filter), filter => Assert.IsType(filter)); } } diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/ControllerSaveTempDataPropertyFilterFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/ControllerSaveTempDataPropertyFilterFactoryTest.cs new file mode 100644 index 0000000000..db8aa9abc3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/ControllerSaveTempDataPropertyFilterFactoryTest.cs @@ -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() + { + new TempDataProperty(propertyInfo, null, null) + }; + + // Act + var filter = factory.CreateInstance(CreateServiceProvider()); + + // Assert + var controllerFilter = Assert.IsType(filter); + Assert.Collection(controllerFilter.TempDataProperties, + property => Assert.Equal("StringProp", property.PropertyInfo.Name)); + } + + private ServiceProvider CreateServiceProvider() + { + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddSingleton(Mock.Of()); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + + return serviceCollection.BuildServiceProvider(); + } + + private class StringController + { + public string StringProp { get; set; } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataPropertyFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/ControllerSaveTempDataPropertyFilterTest.cs similarity index 56% rename from test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataPropertyFilterTest.cs rename to test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/ControllerSaveTempDataPropertyFilterTest.cs index f810ed48b9..eccd8a6d22 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataPropertyFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/ControllerSaveTempDataPropertyFilterTest.cs @@ -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(); + var controllerType = controller.GetType(); + var testProp = controllerType.GetProperty(nameof(TestController.Test)); + var test2Prop = controllerType.GetProperty(nameof(TestController.Test2)); + + filter.TempDataProperties = new List + { + 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(); + var controllerType = controller.GetType(); + var testProp = controllerType.GetProperty(nameof(TestController.Test)); + var test2Prop = controllerType.GetProperty(nameof(TestController.Test2)); + + filter.TempDataProperties = new List + { + 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()) - { - { "TempDataProperty-Test", "Value" } - }; - tempData.Save(); - - var controller = new TestControllerStrings() - { - TempData = tempData, - }; - - var provider = CreateSaveTempDataPropertyFilter(httpContext, tempData: tempData); - provider.Subject = controller; - provider.PropertyHelpers = BuildPropertyHelpers(); - - // Act - provider.ApplyTempDataChanges(httpContext); - - // Assert - Assert.Equal("Value", controller.Test); - Assert.Null(controller.Test2); - } - - private IList BuildPropertyHelpers() - { - var subjectType = typeof(TSubject); - - var properties = subjectType.GetProperties( - BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - - var result = new List(); - - 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 diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterFactoryTest.cs new file mode 100644 index 0000000000..f56320a41d --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterFactoryTest.cs @@ -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(filter); + Assert.Same(factory, pageFilter.FilterFactory); + } + + private ServiceProvider CreateServiceProvider() + { + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddSingleton(Mock.Of()); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + + return serviceCollection.BuildServiceProvider(); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs new file mode 100644 index 0000000000..ecea4a4320 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs @@ -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()) + { + { "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{ + 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()); + tempData.Save(); + + var page = new TestPageString() + { + ViewContext = CreateViewContext(httpContext, tempData) + }; + + var provider = CreatePageSaveTempDataPropertyFilter(httpContext, tempData: tempData, filterFactory: false); + + // Act & Assert + var ex = Assert.Throws(() => 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()); + 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()) + { + { "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 { + 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()) + { + { "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 { + 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(); + factory.Setup(f => f.GetTempData(httpContext)) + .Returns(tempData); + + var propertyFilter = new PageSaveTempDataPropertyFilter(factory.Object); + + if (filterFactory) + { + propertyFilter.FilterFactory = new Mock().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; } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/SaveTempDataFilterTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilterTest.cs rename to test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/SaveTempDataFilterTest.cs diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/TempDataApplicationModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/TempDataApplicationModelProviderTest.cs index 3a24e5aa35..1d2203ad93 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/TempDataApplicationModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/TempDataApplicationModelProviderTest.cs @@ -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(); + var filter = controller.Filters.OfType(); 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] diff --git a/test/WebSites/RazorPagesWebSite/TempData/SetMessageAndRedirect.cshtml b/test/WebSites/RazorPagesWebSite/TempData/SetMessageAndRedirect.cshtml new file mode 100644 index 0000000000..9eeac27791 --- /dev/null +++ b/test/WebSites/RazorPagesWebSite/TempData/SetMessageAndRedirect.cshtml @@ -0,0 +1,10 @@ +@page + +@functions +{ + public IActionResult OnGet() + { + TempData["TempDataProperty-Message"] = "Secret Message"; + return Redirect("~/TempData/TempDataPageModelProperty"); + } +} \ No newline at end of file diff --git a/test/WebSites/RazorPagesWebSite/TempData/TempDataPageModel.cs b/test/WebSites/RazorPagesWebSite/TempData/TempDataPageModel.cs new file mode 100644 index 0000000000..805286e3e9 --- /dev/null +++ b/test/WebSites/RazorPagesWebSite/TempData/TempDataPageModel.cs @@ -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(); + } + } +} diff --git a/test/WebSites/RazorPagesWebSite/TempData/TempDataPageModelProperty.cshtml b/test/WebSites/RazorPagesWebSite/TempData/TempDataPageModelProperty.cshtml new file mode 100644 index 0000000000..50749c4c63 --- /dev/null +++ b/test/WebSites/RazorPagesWebSite/TempData/TempDataPageModelProperty.cshtml @@ -0,0 +1,9 @@ +@page +@model RazorPagesWebSite.TempData.TempDataPageModel + +Message: @Model.Message +@using (Html.BeginForm()) +{ + @Html.AntiForgeryToken() +} +TempData: @TempData["TempDataProperty-Message"]