Fix #5979 - Remove hardcoding of tempdata for pages
This commit is contained in:
parent
c27b07ef3f
commit
dfe04bc917
|
|
@ -141,23 +141,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
|
||||||
private Task BindArgumentsAsync()
|
private Task BindArgumentsAsync()
|
||||||
{
|
{
|
||||||
// This is a temporary workaround.
|
|
||||||
PageSaveTempDataPropertyFilter propertyFilter = null;
|
|
||||||
for (var i = 0; i < _filters.Length; i++)
|
|
||||||
{
|
|
||||||
propertyFilter = _filters[i] as PageSaveTempDataPropertyFilter;
|
|
||||||
if (propertyFilter != null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyFilter != null)
|
|
||||||
{
|
|
||||||
propertyFilter.Subject = _instance;
|
|
||||||
propertyFilter.ApplyTempDataChanges(_pageContext.HttpContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perf: Avoid allocating async state machines where possible. We only need the state
|
// Perf: Avoid allocating async state machines where possible. We only need the state
|
||||||
// machine if you need to bind properties or arguments.
|
// machine if you need to bind properties or arguments.
|
||||||
if (_actionDescriptor.BoundProperties.Count == 0 && (_handler == null || _handler.Parameters.Count == 0))
|
if (_actionDescriptor.BoundProperties.Count == 0 && (_handler == null || _handler.Parameters.Count == 0))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// 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.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
{
|
||||||
|
public class PageSaveTempDataPropertyFilter : SaveTempDataPropertyFilterBase, IPageFilter
|
||||||
|
{
|
||||||
|
public PageSaveTempDataPropertyFilter(ITempDataDictionaryFactory factory)
|
||||||
|
: base(factory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageSaveTempDataPropertyFilterFactory FilterFactory { get; set; }
|
||||||
|
|
||||||
|
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
|
||||||
|
{
|
||||||
|
if (context.HandlerInstance == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatPropertyOfTypeCannotBeNull(
|
||||||
|
nameof(PageHandlerExecutingContext.HandlerInstance),
|
||||||
|
typeof(PageHandlerExecutingContext).Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilterFactory == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatPropertyOfTypeCannotBeNull(
|
||||||
|
nameof(FilterFactory),
|
||||||
|
typeof(PageSaveTempDataPropertyFilter).Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
var tempData = _factory.GetTempData(context.HttpContext);
|
||||||
|
|
||||||
|
Subject = context.HandlerInstance;
|
||||||
|
Properties = FilterFactory.GetTempDataProperties(Subject.GetType());
|
||||||
|
|
||||||
|
SetPropertyVaules(tempData, Subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,13 +4,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
public class PageSaveTempDataPropertyFilterFactory : IFilterFactory
|
public class PageSaveTempDataPropertyFilterFactory : IFilterFactory
|
||||||
{
|
{
|
||||||
public IList<TempDataProperty> TempDataProperties { get; set; }
|
public IList<TempDataProperty> Properties { get; set; }
|
||||||
|
|
||||||
public bool IsReusable => false;
|
public bool IsReusable => false;
|
||||||
|
|
||||||
|
|
@ -32,12 +33,12 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
// TempDataProperties are stored here as a cache for the filter. But in pages by the time we know the type
|
// 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
|
// 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.
|
// call this method to populate its TempDataProperties.
|
||||||
if (TempDataProperties == null)
|
if (Properties == null)
|
||||||
{
|
{
|
||||||
TempDataProperties = SaveTempDataPropertyFilterBase.GetTempDataProperties(modelType);
|
Properties = SaveTempDataPropertyFilterBase.GetTempDataProperties(modelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TempDataProperties;
|
return Properties;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
var service = serviceProvider.GetRequiredService<ControllerSaveTempDataPropertyFilter>();
|
var service = serviceProvider.GetRequiredService<ControllerSaveTempDataPropertyFilter>();
|
||||||
service.TempDataProperties = TempDataProperties;
|
service.Properties = TempDataProperties;
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,65 +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 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,12 +17,12 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the temp data properties which exist on <see cref="Subject"/>
|
/// Describes the temp data properties which exist on <see cref="Subject"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<TempDataProperty> TempDataProperties { get; set; }
|
public IList<TempDataProperty> Properties { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="object"/> which has the temp data properties.
|
/// The <see cref="object"/> which has the temp data properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual object Subject { get; set; }
|
public object Subject { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tracks the values which originally existed in temp data.
|
/// Tracks the values which originally existed in temp data.
|
||||||
|
|
@ -40,17 +40,17 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
/// <param name="tempData">The <see cref="ITempDataDictionary"/> to be updated.</param>
|
/// <param name="tempData">The <see cref="ITempDataDictionary"/> to be updated.</param>
|
||||||
public void OnTempDataSaving(ITempDataDictionary tempData)
|
public void OnTempDataSaving(ITempDataDictionary tempData)
|
||||||
{
|
{
|
||||||
if (Subject != null && OriginalValues != null)
|
if (Subject != null && Properties != null)
|
||||||
{
|
{
|
||||||
foreach (var kvp in OriginalValues)
|
for (var i = 0; i < Properties.Count; i++)
|
||||||
{
|
{
|
||||||
var property = kvp.Key;
|
var property = Properties[i];
|
||||||
var originalValue = kvp.Value;
|
OriginalValues.TryGetValue(property.PropertyInfo, out var originalValue);
|
||||||
|
|
||||||
var newValue = property.GetValue(Subject);
|
var newValue = property.GetValue(Subject);
|
||||||
if (newValue != null && !newValue.Equals(originalValue))
|
if (newValue != null && !newValue.Equals(originalValue))
|
||||||
{
|
{
|
||||||
tempData[Prefix + property.Name] = newValue;
|
tempData[property.TempDataKey] = newValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +74,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
results.Add(new TempDataProperty(
|
results.Add(new TempDataProperty(
|
||||||
|
Prefix + propertyHelper.Name,
|
||||||
propertyHelper.Property,
|
propertyHelper.Property,
|
||||||
propertyHelper.GetValue,
|
propertyHelper.GetValue,
|
||||||
propertyHelper.SetValue));
|
propertyHelper.SetValue));
|
||||||
|
|
@ -109,14 +110,14 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
/// <param name="subject">The <see cref="object"/> which will have it's properties set.</param>
|
/// <param name="subject">The <see cref="object"/> which will have it's properties set.</param>
|
||||||
protected void SetPropertyVaules(ITempDataDictionary tempData, object subject)
|
protected void SetPropertyVaules(ITempDataDictionary tempData, object subject)
|
||||||
{
|
{
|
||||||
if (TempDataProperties == null)
|
if (Properties == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < TempDataProperties.Count; i++)
|
for (var i = 0; i < Properties.Count; i++)
|
||||||
{
|
{
|
||||||
var property = TempDataProperties[i];
|
var property = Properties[i];
|
||||||
var value = tempData[Prefix + property.PropertyInfo.Name];
|
var value = tempData[Prefix + property.PropertyInfo.Name];
|
||||||
|
|
||||||
OriginalValues[property.PropertyInfo] = value;
|
OriginalValues[property.PropertyInfo] = value;
|
||||||
|
|
@ -12,13 +12,16 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
|
|
||||||
private readonly Action<object, object> _setter;
|
private readonly Action<object, object> _setter;
|
||||||
|
|
||||||
public TempDataProperty(PropertyInfo propertyInfo, Func<object, object> getter, Action<object, object> setter)
|
public TempDataProperty(string tempDataKey, PropertyInfo propertyInfo, Func<object, object> getter, Action<object, object> setter)
|
||||||
{
|
{
|
||||||
|
TempDataKey = tempDataKey;
|
||||||
PropertyInfo = propertyInfo;
|
PropertyInfo = propertyInfo;
|
||||||
_getter = getter;
|
_getter = getter;
|
||||||
_setter = setter;
|
_setter = setter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string TempDataKey { get; }
|
||||||
|
|
||||||
public PropertyInfo PropertyInfo { get; }
|
public PropertyInfo PropertyInfo { get; }
|
||||||
|
|
||||||
public object GetValue(object obj)
|
public object GetValue(object obj)
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
public class PageSaveTempDataPropertyFilterFactoryTest
|
public class PageSaveTempDataPropertyFilterFactoryTest
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
// 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.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
|
{
|
||||||
|
public class PageSaveTempDataPropertyFilterTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void OnTempDataSaving_PopulatesTempDataWithNewValuesFromPageProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
||||||
|
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
|
||||||
|
|
||||||
|
var page = new TestPage()
|
||||||
|
{
|
||||||
|
Test = "TestString",
|
||||||
|
Test2 = "Test2",
|
||||||
|
};
|
||||||
|
|
||||||
|
var filter = CreatePageSaveTempDataPropertyFilter(tempData);
|
||||||
|
filter.Subject = page;
|
||||||
|
|
||||||
|
var pageType = page.GetType();
|
||||||
|
|
||||||
|
var testProperty = pageType.GetProperty(nameof(TestPage.Test));
|
||||||
|
var test2Property = pageType.GetProperty(nameof(TestPage.Test2));
|
||||||
|
|
||||||
|
filter.OriginalValues[testProperty] = "SomeValue";
|
||||||
|
filter.OriginalValues[test2Property] = "Test2";
|
||||||
|
|
||||||
|
filter.Properties = new List<TempDataProperty>
|
||||||
|
{
|
||||||
|
new TempDataProperty("TempDataProperty-Test", testProperty, testProperty.GetValue, testProperty.SetValue),
|
||||||
|
new TempDataProperty("TempDataProperty-Test2", test2Property, test2Property.GetValue, test2Property.SetValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
filter.OnTempDataSaving(tempData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("TestString", page.Test);
|
||||||
|
Assert.Equal("TestString", tempData["TempDataProperty-Test"]);
|
||||||
|
Assert.False(tempData.ContainsKey("TestDataProperty-Test2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OnPageExecuting_NullFilterFactory_Throws()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
|
||||||
|
tempData.Save();
|
||||||
|
|
||||||
|
var page = new TestPage();
|
||||||
|
|
||||||
|
var filter = CreatePageSaveTempDataPropertyFilter(tempData, filterFactory: false);
|
||||||
|
|
||||||
|
var context = new PageHandlerExecutingContext(
|
||||||
|
new PageContext()
|
||||||
|
{
|
||||||
|
ActionDescriptor = new CompiledPageActionDescriptor(),
|
||||||
|
HttpContext = httpContext,
|
||||||
|
RouteData = new RouteData(),
|
||||||
|
},
|
||||||
|
Array.Empty<IFilterMetadata>(),
|
||||||
|
null,
|
||||||
|
new Dictionary<string, object>(),
|
||||||
|
page);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var ex = Assert.Throws<InvalidOperationException>(() => filter.OnPageHandlerExecuting(context));
|
||||||
|
Assert.Contains("FilterFactory", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OnPageExecuting_ToPageModel_SetsPropertyValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
||||||
|
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||||
|
{
|
||||||
|
{ "TempDataProperty-Test", "Value" }
|
||||||
|
};
|
||||||
|
tempData.Save();
|
||||||
|
|
||||||
|
var pageModel = new TestPageModel();
|
||||||
|
|
||||||
|
var filter = CreatePageSaveTempDataPropertyFilter(tempData);
|
||||||
|
filter.Subject = pageModel;
|
||||||
|
|
||||||
|
var pageType = typeof(TestPageModel);
|
||||||
|
var testProperty = pageType.GetProperty(nameof(TestPageModel.Test));
|
||||||
|
var test2Property = pageType.GetProperty(nameof(TestPageModel.Test2));
|
||||||
|
|
||||||
|
var context = new PageHandlerExecutingContext(
|
||||||
|
new PageContext()
|
||||||
|
{
|
||||||
|
ActionDescriptor = new CompiledPageActionDescriptor(),
|
||||||
|
HttpContext = httpContext,
|
||||||
|
RouteData = new RouteData(),
|
||||||
|
},
|
||||||
|
Array.Empty<IFilterMetadata>(),
|
||||||
|
null,
|
||||||
|
new Dictionary<string, object>(),
|
||||||
|
pageModel);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
filter.OnPageHandlerExecuting(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("Value", pageModel.Test);
|
||||||
|
Assert.Null(pageModel.Test2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OnPageExecuting_ToPage_SetsPropertyValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
||||||
|
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||||
|
{
|
||||||
|
{ "TempDataProperty-Test", "Value" }
|
||||||
|
};
|
||||||
|
tempData.Save();
|
||||||
|
|
||||||
|
var page = new TestPage()
|
||||||
|
{
|
||||||
|
ViewContext = CreateViewContext(httpContext, tempData)
|
||||||
|
};
|
||||||
|
|
||||||
|
var filter = CreatePageSaveTempDataPropertyFilter(tempData);
|
||||||
|
filter.Subject = page;
|
||||||
|
|
||||||
|
var pageType = page.GetType();
|
||||||
|
var testProperty = pageType.GetProperty(nameof(TestPage.Test));
|
||||||
|
var test2Property = pageType.GetProperty(nameof(TestPage.Test2));
|
||||||
|
|
||||||
|
var context = new PageHandlerExecutingContext(
|
||||||
|
new PageContext()
|
||||||
|
{
|
||||||
|
ActionDescriptor = new CompiledPageActionDescriptor(),
|
||||||
|
HttpContext = httpContext,
|
||||||
|
RouteData = new RouteData(),
|
||||||
|
},
|
||||||
|
Array.Empty<IFilterMetadata>(),
|
||||||
|
null,
|
||||||
|
new Dictionary<string, object>(),
|
||||||
|
page);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
filter.OnPageHandlerExecuting(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("Value", page.Test);
|
||||||
|
Assert.Null(page.Test2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OnPageExecuting_InitializesAndSavesProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
||||||
|
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>())
|
||||||
|
{
|
||||||
|
{ "TempDataProperty-Test", "Value" }
|
||||||
|
};
|
||||||
|
tempData.Save();
|
||||||
|
|
||||||
|
var pageModel = new TestPageModel();
|
||||||
|
|
||||||
|
var filter = CreatePageSaveTempDataPropertyFilter(tempData);
|
||||||
|
filter.Subject = pageModel;
|
||||||
|
|
||||||
|
var factory = filter.FilterFactory;
|
||||||
|
|
||||||
|
var pageType = typeof(TestPageModel);
|
||||||
|
var testProperty = pageType.GetProperty(nameof(TestPageModel.Test));
|
||||||
|
var test2Property = pageType.GetProperty(nameof(TestPageModel.Test2));
|
||||||
|
|
||||||
|
filter.Properties = new List<TempDataProperty>
|
||||||
|
{
|
||||||
|
new TempDataProperty("TempDataProperty-Test", testProperty, testProperty.GetValue, testProperty.SetValue),
|
||||||
|
new TempDataProperty("TempDataProperty-Test2", test2Property, test2Property.GetValue, test2Property.SetValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
var context = new PageHandlerExecutingContext(
|
||||||
|
new PageContext()
|
||||||
|
{
|
||||||
|
ActionDescriptor = new CompiledPageActionDescriptor(),
|
||||||
|
HttpContext = httpContext,
|
||||||
|
RouteData = new RouteData(),
|
||||||
|
},
|
||||||
|
Array.Empty<IFilterMetadata>(),
|
||||||
|
null,
|
||||||
|
new Dictionary<string, object>(),
|
||||||
|
pageModel);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
filter.OnPageHandlerExecuting(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
filter.Properties.OrderBy(p => p.PropertyInfo.Name),
|
||||||
|
p => Assert.Equal(testProperty, p.PropertyInfo),
|
||||||
|
p => Assert.Equal(test2Property, p.PropertyInfo));
|
||||||
|
|
||||||
|
Assert.Same(filter.Properties, factory.Properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ViewContext 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 ViewContext(
|
||||||
|
actionContext,
|
||||||
|
NullView.Instance,
|
||||||
|
viewData,
|
||||||
|
tempData,
|
||||||
|
TextWriter.Null,
|
||||||
|
new HtmlHelperOptions());
|
||||||
|
|
||||||
|
return viewContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageSaveTempDataPropertyFilter CreatePageSaveTempDataPropertyFilter(
|
||||||
|
TempDataDictionary tempData,
|
||||||
|
bool filterFactory = true)
|
||||||
|
{
|
||||||
|
var factory = new Mock<ITempDataDictionaryFactory>();
|
||||||
|
factory
|
||||||
|
.Setup(f => f.GetTempData(It.IsAny<HttpContext>()))
|
||||||
|
.Returns(tempData);
|
||||||
|
|
||||||
|
var propertyFilter = new PageSaveTempDataPropertyFilter(factory.Object);
|
||||||
|
|
||||||
|
if (filterFactory)
|
||||||
|
{
|
||||||
|
propertyFilter.FilterFactory = Mock.Of<PageSaveTempDataPropertyFilterFactory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return propertyFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestPage : Page
|
||||||
|
{
|
||||||
|
[TempData]
|
||||||
|
public string Test { get; set; }
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string Test2 { get; set; }
|
||||||
|
|
||||||
|
public override Task ExecuteAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestPageModel : PageModel
|
||||||
|
{
|
||||||
|
[TempData]
|
||||||
|
public string Test { get; set; }
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string Test2 { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,16 +19,16 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
|
|
||||||
factory.TempDataProperties = new List<TempDataProperty>()
|
factory.TempDataProperties = new List<TempDataProperty>()
|
||||||
{
|
{
|
||||||
new TempDataProperty(propertyInfo, null, null)
|
new TempDataProperty("TempDataProperty-StringProp", propertyInfo, null, null)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var filter = factory.CreateInstance(CreateServiceProvider());
|
var filter = factory.CreateInstance(CreateServiceProvider());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var controllerFilter = Assert.IsType<ControllerSaveTempDataPropertyFilter>(filter);
|
Assert.Collection(
|
||||||
Assert.Collection(controllerFilter.TempDataProperties,
|
Assert.IsType<ControllerSaveTempDataPropertyFilter>(filter).Properties,
|
||||||
property => Assert.Equal("StringProp", property.PropertyInfo.Name));
|
property => Assert.Equal(propertyInfo, property.PropertyInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceProvider CreateServiceProvider()
|
private ServiceProvider CreateServiceProvider()
|
||||||
|
|
@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
|
|
||||||
var controllerType = controller.GetType();
|
var controllerType = controller.GetType();
|
||||||
var testProp = controllerType.GetProperty(nameof(TestController.Test));
|
var testProperty = controllerType.GetProperty(nameof(TestController.Test));
|
||||||
var test2Prop = controllerType.GetProperty(nameof(TestController.Test2));
|
var test2Property = controllerType.GetProperty(nameof(TestController.Test2));
|
||||||
|
|
||||||
filter.TempDataProperties = new List<TempDataProperty>
|
filter.Properties = new List<TempDataProperty>
|
||||||
{
|
{
|
||||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
new TempDataProperty("TempDataProperty-Test", testProperty, testProperty.GetValue, testProperty.SetValue),
|
||||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
new TempDataProperty("TempDataProperty-Test2", test2Property, test2Property.GetValue, test2Property.SetValue)
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new ActionExecutingContext(
|
var context = new ActionExecutingContext(
|
||||||
|
|
@ -73,13 +73,13 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
|
|
||||||
var controllerType = controller.GetType();
|
var controllerType = controller.GetType();
|
||||||
var testProp = controllerType.GetProperty(nameof(TestController.Test));
|
var testProperty = controllerType.GetProperty(nameof(TestController.Test));
|
||||||
var test2Prop = controllerType.GetProperty(nameof(TestController.Test2));
|
var test2Property = controllerType.GetProperty(nameof(TestController.Test2));
|
||||||
|
|
||||||
filter.TempDataProperties = new List<TempDataProperty>
|
filter.Properties = new List<TempDataProperty>
|
||||||
{
|
{
|
||||||
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
|
new TempDataProperty("TempDataProperty-Test", testProperty, testProperty.GetValue, testProperty.SetValue),
|
||||||
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
|
new TempDataProperty("TempDataProperty-Test2", test2Property, test2Property.GetValue, test2Property.SetValue)
|
||||||
};
|
};
|
||||||
|
|
||||||
var context = new ActionExecutingContext(
|
var context = new ActionExecutingContext(
|
||||||
|
|
@ -107,7 +107,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
TempDataDictionary tempData)
|
TempDataDictionary tempData)
|
||||||
{
|
{
|
||||||
var factory = new Mock<ITempDataDictionaryFactory>();
|
var factory = new Mock<ITempDataDictionaryFactory>();
|
||||||
factory.Setup(f => f.GetTempData(httpContext))
|
factory
|
||||||
|
.Setup(f => f.GetTempData(httpContext))
|
||||||
.Returns(tempData);
|
.Returns(tempData);
|
||||||
|
|
||||||
return new ControllerSaveTempDataPropertyFilter(factory.Object);
|
return new ControllerSaveTempDataPropertyFilter(factory.Object);
|
||||||
|
|
@ -1,251 +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.IO;
|
|
||||||
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.Mvc.Rendering;
|
|
||||||
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 ViewContext 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 ViewContext(
|
|
||||||
actionContext,
|
|
||||||
NullView.Instance,
|
|
||||||
viewData,
|
|
||||||
tempData,
|
|
||||||
TextWriter.Null,
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue