diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
index ce3db79de4..720dbacd87 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
@@ -1285,7 +1285,7 @@ namespace Microsoft.AspNetCore.Mvc.Core
=> string.Format(CultureInfo.CurrentCulture, GetString("NoRoutesMatchedForPage"), p0);
///
- /// The relative page path '{0}' can only can only be used while executing a Razor Page. Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.
+ /// The relative page path '{0}' can only be used while executing a Razor Page. Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.
///
internal static string UrlHelper_RelativePagePathIsNotSupported
{
@@ -1293,7 +1293,7 @@ namespace Microsoft.AspNetCore.Mvc.Core
}
///
- /// The relative page path '{0}' can only can only be used while executing a Razor Page. Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.
+ /// The relative page path '{0}' can only be used while executing a Razor Page. Specify a root relative path with a leading '/' to generate a URL outside of a Razor Page.
///
internal static string FormatUrlHelper_RelativePagePathIsNotSupported(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("UrlHelper_RelativePagePathIsNotSupported"), p0);
diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorPagePropertyActivator.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorPagePropertyActivator.cs
index 67b90cc6a4..8453d1e006 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorPagePropertyActivator.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorPagePropertyActivator.cs
@@ -3,12 +3,12 @@
using System;
using System.Diagnostics;
-using System.Linq.Expressions;
using System.Reflection;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
@@ -16,8 +16,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class RazorPagePropertyActivator
{
- private delegate ViewDataDictionary CreateViewDataNestedDelegate(ViewDataDictionary source);
- private delegate ViewDataDictionary CreateViewDataRootDelegate(ModelStateDictionary modelState);
+ private readonly IModelMetadataProvider _metadataProvider;
+ private readonly Func _rootFactory;
+ private readonly Func _nestedFactory;
+ private readonly Type _viewDataDictionaryType;
+ private readonly PropertyActivator[] _propertyActivators;
public RazorPagePropertyActivator(
Type pageType,
@@ -25,26 +28,19 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
IModelMetadataProvider metadataProvider,
PropertyValueAccessors propertyValueAccessors)
{
- var viewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType);
- ViewDataDictionaryType = viewDataType;
- CreateViewDataNested = GetCreateViewDataNested(viewDataType);
- CreateViewDataRoot = GetCreateViewDataRoot(viewDataType, metadataProvider);
+ _metadataProvider = metadataProvider;
- PropertyActivators = PropertyActivator.GetPropertiesToActivate(
+ _viewDataDictionaryType = typeof(ViewDataDictionary<>).MakeGenericType(modelType);
+ _rootFactory = ViewDataDictionaryFactory.CreateFactory(modelType.GetTypeInfo());
+ _nestedFactory = ViewDataDictionaryFactory.CreateNestedFactory(modelType.GetTypeInfo());
+
+ _propertyActivators = PropertyActivator.GetPropertiesToActivate(
pageType,
typeof(RazorInjectAttribute),
propertyInfo => CreateActivateInfo(propertyInfo, propertyValueAccessors),
includeNonPublic: true);
}
- private PropertyActivator[] PropertyActivators { get; }
-
- private Type ViewDataDictionaryType { get; }
-
- private CreateViewDataNestedDelegate CreateViewDataNested { get; }
-
- private CreateViewDataRootDelegate CreateViewDataRoot { get; }
-
public void Activate(object page, ViewContext context)
{
if (context == null)
@@ -54,9 +50,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
context.ViewData = CreateViewDataDictionary(context);
- for (var i = 0; i < PropertyActivators.Length; i++)
+ for (var i = 0; i < _propertyActivators.Length; i++)
{
- var activateInfo = PropertyActivators[i];
+ var activateInfo = _propertyActivators[i];
activateInfo.Activate(page, context);
}
}
@@ -68,58 +64,17 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
if (context.ViewData == null)
{
// Create ViewDataDictionary(IModelMetadataProvider, ModelStateDictionary).
- return CreateViewDataRoot(context.ModelState);
+ return _rootFactory(_metadataProvider, context.ModelState);
}
- else if (context.ViewData.GetType() != ViewDataDictionaryType)
+ else if (context.ViewData.GetType() != _viewDataDictionaryType)
{
// Create ViewDataDictionary(ViewDataDictionary).
- return CreateViewDataNested(context.ViewData);
+ return _nestedFactory(context.ViewData);
}
return context.ViewData;
}
- private static CreateViewDataNestedDelegate GetCreateViewDataNested(Type viewDataDictionaryType)
- {
- var parameterTypes = new Type[] { typeof(ViewDataDictionary) };
- var matchingConstructor = viewDataDictionaryType.GetConstructor(parameterTypes);
- Debug.Assert(matchingConstructor != null);
-
- var parameters = new ParameterExpression[] { Expression.Parameter(parameterTypes[0]) };
- var newExpression = Expression.New(matchingConstructor, parameters);
- var castNewCall = Expression.Convert(
- newExpression,
- typeof(ViewDataDictionary));
- var lambda = Expression.Lambda(castNewCall, parameters);
- return lambda.Compile();
- }
-
- private static CreateViewDataRootDelegate GetCreateViewDataRoot(
- Type viewDataDictionaryType,
- IModelMetadataProvider provider)
- {
- var parameterTypes = new[]
- {
- typeof(IModelMetadataProvider),
- typeof(ModelStateDictionary)
- };
- var matchingConstructor = viewDataDictionaryType.GetConstructor(parameterTypes);
- Debug.Assert(matchingConstructor != null);
-
- var parameterExpression = Expression.Parameter(parameterTypes[1]);
- var parameters = new Expression[]
- {
- Expression.Constant(provider),
- parameterExpression
- };
- var newExpression = Expression.New(matchingConstructor, parameters);
- var castNewCall = Expression.Convert(
- newExpression,
- typeof(ViewDataDictionary));
- var lambda = Expression.Lambda(castNewCall, parameterExpression);
- return lambda.Compile();
- }
-
private static PropertyActivator CreateActivateInfo(
PropertyInfo property,
PropertyValueAccessors valueAccessors)
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs
index 5e194b0d28..7cf4d35c01 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs
@@ -113,7 +113,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton();
services.TryAddSingleton();
- services.TryAddSingleton();
+ services.TryAddSingleton();
services.TryAddSingleton();
services.TryAddSingleton();
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageActivatorProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageActivatorProvider.cs
index 98ebb5a915..80578d5f17 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageActivatorProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageActivatorProvider.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.AspNetCore.Mvc.RazorPages
{
@@ -15,13 +16,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
///
/// The .
/// The delegate used to activate the page.
- Func CreateActivator(CompiledPageActionDescriptor descriptor);
+ Func CreateActivator(CompiledPageActionDescriptor descriptor);
///
/// Releases a Razor page.
///
/// The .
/// The delegate used to dispose the activated page.
- Action CreateReleaser(CompiledPageActionDescriptor descriptor);
+ Action CreateReleaser(CompiledPageActionDescriptor descriptor);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageFactoryProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageFactoryProvider.cs
index dff6addb1a..a3b366784c 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageFactoryProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/IPageFactoryProvider.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.AspNetCore.Mvc.RazorPages
{
@@ -15,13 +16,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
///
/// The .
/// The Razor page factory.
- Func CreatePageFactory(CompiledPageActionDescriptor descriptor);
+ Func CreatePageFactory(CompiledPageActionDescriptor descriptor);
///
/// Releases a Razor page.
///
/// The .
/// The delegate used to release the created page.
- Action CreatePageDisposer(CompiledPageActionDescriptor descriptor);
+ Action CreatePageDisposer(CompiledPageActionDescriptor descriptor);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageActivator.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageActivatorProvider.cs
similarity index 66%
rename from src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageActivator.cs
rename to src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageActivatorProvider.cs
index 5b06a51115..f0ec8404a9 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageActivator.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageActivatorProvider.cs
@@ -4,18 +4,19 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
+using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
///
/// that uses type activation to create Pages.
///
- public class DefaultPageActivator : IPageActivatorProvider
+ public class DefaultPageActivatorProvider : IPageActivatorProvider
{
- private readonly Action _disposer = Dispose;
+ private readonly Action _disposer = Dispose;
///
- public virtual Func CreateActivator(CompiledPageActionDescriptor actionDescriptor)
+ public virtual Func CreateActivator(CompiledPageActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
{
@@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
return CreatePageFactory(pageTypeInfo);
}
- public virtual Action CreateReleaser(CompiledPageActionDescriptor actionDescriptor)
+ public virtual Action CreateReleaser(CompiledPageActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
{
@@ -49,27 +50,33 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
return null;
}
- private static Func CreatePageFactory(Type pageTypeInfo)
+ private static Func CreatePageFactory(Type pageTypeInfo)
{
- var parameter = Expression.Parameter(typeof(PageContext), "pageContext");
+ var parameter1 = Expression.Parameter(typeof(PageContext), "pageContext");
+ var parameter2 = Expression.Parameter(typeof(ViewContext), "viewContext");
// new Page();
var newExpression = Expression.New(pageTypeInfo);
// () => new Page();
var pageFactory = Expression
- .Lambda>(newExpression, parameter)
+ .Lambda>(newExpression, parameter1, parameter2)
.Compile();
return pageFactory;
}
- private static void Dispose(PageContext context, object page)
+ private static void Dispose(PageContext context, ViewContext viewContext, object page)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
+ if (viewContext == null)
+ {
+ throw new ArgumentNullException(nameof(viewContext));
+ }
+
if (page == null)
{
throw new ArgumentNullException(nameof(page));
@@ -77,20 +84,5 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
((IDisposable)page).Dispose();
}
-
- private static void NullDisposer(PageContext context, object page)
- {
- if (context == null)
- {
- throw new ArgumentNullException(nameof(context));
- }
-
- if (page == null)
- {
- throw new ArgumentNullException(nameof(page));
- }
-
- // No-op
- }
}
}
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageFactory.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageFactory.cs
index f815b6d4ff..e4b21d0938 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageFactory.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultPageFactory.cs
@@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
};
}
- public virtual Func CreatePageFactory(CompiledPageActionDescriptor actionDescriptor)
+ public virtual Func CreatePageFactory(CompiledPageActionDescriptor actionDescriptor)
{
if (!typeof(Page).GetTypeInfo().IsAssignableFrom(actionDescriptor.PageTypeInfo))
{
@@ -57,17 +57,18 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
_modelMetadataProvider,
_propertyAccessors);
- return (context) =>
+ return (pageContext, viewContext) =>
{
- var page = (Page)activatorFactory(context);
- page.PageContext = context;
- page.Path = context.ActionDescriptor.RelativePath;
- propertyActivator.Activate(page, context);
+ var page = (Page)activatorFactory(pageContext, viewContext);
+ page.PageContext = pageContext;
+ page.Path = pageContext.ActionDescriptor.RelativePath;
+ page.ViewContext = viewContext;
+ propertyActivator.Activate(page, viewContext);
return page;
};
}
- public virtual Action CreatePageDisposer(CompiledPageActionDescriptor descriptor)
+ public virtual Action CreatePageDisposer(CompiledPageActionDescriptor descriptor)
{
if (descriptor == null)
{
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageResultExecutor.cs
index 629a2b1f3e..93e4ec574d 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageResultExecutor.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageResultExecutor.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
+using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
@@ -65,9 +66,21 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
pageContext.ViewData.Model = result.Model;
}
- var view = new RazorView(_razorViewEngine, _razorPageActivator, pageContext.ViewStarts, result.Page, _htmlEncoder);
- pageContext.View = view;
- return ExecuteAsync(pageContext, result.ContentType, result.StatusCode);
+ var viewStarts = new IRazorPage[pageContext.ViewStartFactories.Count];
+ for (var i = 0; i < pageContext.ViewStartFactories.Count; i++)
+ {
+ viewStarts[i] = pageContext.ViewStartFactories[i]();
+ }
+
+ var viewContext = result.Page.ViewContext;
+ viewContext.View = new RazorView(
+ _razorViewEngine,
+ _razorPageActivator,
+ viewStarts,
+ result.Page,
+ _htmlEncoder);
+
+ return ExecuteAsync(viewContext, result.ContentType, result.StatusCode);
}
}
}
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs
index b9443fa298..e9f6642963 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionInvoker.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
@@ -13,8 +14,11 @@ using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
@@ -23,9 +27,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
private readonly IPageHandlerMethodSelector _selector;
private readonly PageContext _pageContext;
private readonly ParameterBinder _parameterBinder;
+ private readonly ITempDataDictionaryFactory _tempDataFactory;
+ private readonly HtmlHelperOptions _htmlHelperOptions;
+ private CompiledPageActionDescriptor _actionDescriptor;
private Page _page;
private object _model;
+ private ViewContext _viewContext;
private ExceptionContext _exceptionContext;
public PageActionInvoker(
@@ -36,7 +44,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
IFilterMetadata[] filterMetadata,
IList valueProviderFactories,
PageActionInvokerCacheEntry cacheEntry,
- ParameterBinder parameterBinder)
+ ParameterBinder parameterBinder,
+ ITempDataDictionaryFactory tempDataFactory,
+ HtmlHelperOptions htmlHelperOptions)
: base(
diagnosticSource,
logger,
@@ -48,9 +58,17 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
_pageContext = pageContext;
CacheEntry = cacheEntry;
_parameterBinder = parameterBinder;
+ _tempDataFactory = tempDataFactory;
+ _htmlHelperOptions = htmlHelperOptions;
+
+ _actionDescriptor = pageContext.ActionDescriptor;
}
- public PageActionInvokerCacheEntry CacheEntry { get; }
+ // Internal for testing
+ internal PageActionInvokerCacheEntry CacheEntry { get; }
+
+ // Internal for testing
+ internal PageContext PageContext => _pageContext;
///
/// for details on what the variables in this method represent.
@@ -77,7 +95,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
if (_page != null && CacheEntry.ReleasePage != null)
{
- CacheEntry.ReleasePage(_pageContext, _page);
+ CacheEntry.ReleasePage(_pageContext, _viewContext, _page);
}
}
@@ -303,47 +321,36 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
}
}
- private async Task ExecutePageAsync()
+ private Task ExecutePageAsync()
{
- var actionDescriptor = _pageContext.ActionDescriptor;
- _page = (Page)CacheEntry.PageFactory(_pageContext);
- _pageContext.Page = _page;
_pageContext.ValueProviderFactories = _valueProviderFactories;
- IRazorPage[] viewStarts;
-
- if (CacheEntry.ViewStartFactories == null || CacheEntry.ViewStartFactories.Count == 0)
+ // There's a fork in the road here between the case where we have a full-fledged PageModel
+ // vs just a Page. We need to know up front because we want to execute handler methods
+ // on the PageModel without instantiating the Page or ViewContext.
+ var hasPageModel = _actionDescriptor.HandlerTypeInfo != _actionDescriptor.PageTypeInfo;
+ if (hasPageModel)
{
- viewStarts = Array.Empty();
+ return ExecutePageWithPageModelAsync();
}
else
{
- viewStarts = new IRazorPage[CacheEntry.ViewStartFactories.Count];
- for (var i = 0; i < viewStarts.Length; i++)
- {
- var pageFactory = CacheEntry.ViewStartFactories[i];
- viewStarts[i] = pageFactory();
- }
+ return ExecutePageWithoutPageModelAsync();
}
- _pageContext.ViewStarts = viewStarts;
+ }
- if (actionDescriptor.ModelTypeInfo == actionDescriptor.PageTypeInfo)
- {
- _model = _page;
- }
- else
- {
- _model = CacheEntry.ModelFactory(_pageContext);
- }
-
- if (_model != null)
- {
- _pageContext.ViewData.Model = _model;
- }
+ private async Task ExecutePageWithPageModelAsync()
+ {
+ // Since this is a PageModel, we need to activate it, and then run a handler method on the model.
+ //
+ // We also know that the model is the pagemodel at this point.
+ Debug.Assert(_actionDescriptor.ModelTypeInfo == _actionDescriptor.HandlerTypeInfo);
+ _model = CacheEntry.ModelFactory(_pageContext);
+ _pageContext.ViewData.Model = _model;
if (CacheEntry.PropertyBinder != null)
{
- await CacheEntry.PropertyBinder(_page, _model);
+ await CacheEntry.PropertyBinder(_pageContext, _model);
}
// This is a workaround for not yet having proper filter for Pages.
@@ -359,44 +366,82 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
if (propertyFilter != null)
{
- object subject = _page;
-
- if (_model != null)
- {
- subject = _model;
- }
-
- propertyFilter.Subject = subject;
+ propertyFilter.Subject = _model;
propertyFilter.ApplyTempDataChanges(_pageContext.HttpContext);
}
- IActionResult result = null;
-
- var handler = _selector.Select(_pageContext);
- if (handler != null)
+ _result = await ExecuteHandlerMethod(_model);
+ if (_result is PageResult pageResult)
{
- var arguments = await GetArguments(handler);
+ // If we get here, we are going to render the page, so we need to create it and then initialize
+ // the context so we can run the result.
+ _viewContext = new ViewContext(
+ _pageContext,
+ NullView.Instance,
+ _pageContext.ViewData,
+ _tempDataFactory.GetTempData(_pageContext.HttpContext),
+ TextWriter.Null,
+ _htmlHelperOptions);
- Func
- public virtual PageResult Page() => new PageResult(this);
+ public virtual PageResult Page() => new PageResult();
///
/// Creates a object that redirects to the specified .
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/PageContext.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/PageContext.cs
index c95a901ec3..a1cdcef1a8 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/PageContext.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/PageContext.cs
@@ -2,25 +2,22 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections;
using System.Collections.Generic;
-using System.IO;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
-using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
-using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
namespace Microsoft.AspNetCore.Mvc.RazorPages
{
///
/// The context associated with the current request for a Razor page.
///
- public class PageContext : ViewContext
+ public class PageContext : ActionContext
{
private CompiledPageActionDescriptor _actionDescriptor;
- private Page _page;
private IList _valueProviderFactories;
+ private ViewDataDictionary _viewData;
+ private IList> _viewStartFactories;
///
/// Creates an empty .
@@ -36,53 +33,32 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// Initializes a new instance of .
///
/// The .
- /// The .
- /// The .
- /// The to apply to this instance.
- public PageContext(
- ActionContext actionContext,
- ViewDataDictionary viewData,
- ITempDataDictionary tempDataDictionary,
- HtmlHelperOptions htmlHelperOptions)
- : base(actionContext, NullView.Instance, viewData, tempDataDictionary, TextWriter.Null, htmlHelperOptions)
+ public PageContext(ActionContext actionContext)
+ : base(actionContext)
{
}
///
/// Gets or sets the .
///
- public new CompiledPageActionDescriptor ActionDescriptor
+ public virtual new CompiledPageActionDescriptor ActionDescriptor
{
get
{
return _actionDescriptor;
}
set
- {
- _actionDescriptor = value;
- base.ActionDescriptor = value;
- }
- }
-
- public Page Page
- {
- get { return _page; }
- set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
- _page = value;
+ _actionDescriptor = value;
+ base.ActionDescriptor = value;
}
}
- ///
- /// Gets or sets the applicable _ViewStart instances.
- ///
- public IReadOnlyList ViewStarts { get; set; }
-
///
/// Gets or sets the list of instances for the current request.
///
@@ -107,5 +83,45 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
_valueProviderFactories = value;
}
}
+
+ ///
+ /// Gets or sets .
+ ///
+ public virtual ViewDataDictionary ViewData
+ {
+ get
+ {
+ return _viewData;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _viewData = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the applicable _ViewStart instances.
+ ///
+ public virtual IList> ViewStartFactories
+ {
+ get
+ {
+ return _viewStartFactories;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _viewStartFactories = value;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/PageModel.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/PageModel.cs
index bbe0df2d4e..a7daf7ba4f 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/PageModel.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/PageModel.cs
@@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
@@ -25,48 +24,18 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
[PagesBaseClass]
public abstract class PageModel
{
- private IObjectModelValidator _objectValidator;
private IModelMetadataProvider _metadataProvider;
private IModelBinderFactory _modelBinderFactory;
+ private IObjectModelValidator _objectValidator;
+ private ITempDataDictionary _tempData;
private IUrlHelper _urlHelper;
- ///
- /// Gets or sets the .
- ///
- public IUrlHelper Url
- {
- get
- {
- if (_urlHelper == null)
- {
- var factory = HttpContext?.RequestServices?.GetRequiredService();
- _urlHelper = factory?.GetUrlHelper(PageContext);
- }
-
- return _urlHelper;
- }
- set
- {
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
-
- _urlHelper = value;
- }
- }
-
///
/// Gets the .
///
[PageContext]
public PageContext PageContext { get; set; }
- ///
- /// Gets the .
- ///
- public ViewContext ViewContext => PageContext;
-
///
/// Gets the .
///
@@ -98,10 +67,61 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
public ClaimsPrincipal User => HttpContext?.User;
///
- /// Gets the from the .
+ /// Gets or sets used by .
///
- /// Returns null if is null.
- public ITempDataDictionary TempData => PageContext?.TempData;
+ public ITempDataDictionary TempData
+ {
+ get
+ {
+ if (_tempData == null)
+ {
+ var factory = HttpContext?.RequestServices?.GetRequiredService();
+ _tempData = factory?.GetTempData(HttpContext);
+ }
+
+ return _tempData;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _tempData = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the .
+ ///
+ public IUrlHelper Url
+ {
+ get
+ {
+ if (_urlHelper == null)
+ {
+ var factory = HttpContext?.RequestServices?.GetRequiredService();
+ _urlHelper = factory?.GetUrlHelper(PageContext);
+ }
+
+ return _urlHelper;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _urlHelper = value;
+ }
+ }
+
+ ///
+ /// Gets or sets used by .
+ ///
+ public ViewDataDictionary ViewData => PageContext?.ViewData;
private IObjectModelValidator ObjectValidator
{
@@ -142,11 +162,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
}
}
- ///
- /// Gets the .
- ///
- public ViewDataDictionary ViewData => PageContext?.ViewData;
-
///
/// Updates the specified instance using values from the 's current
/// .
@@ -797,7 +812,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// Creates a object that renders the page.
///
/// The .
- public virtual PageResult Page() => new PageResult(PageContext.Page, this);
+ public virtual PageResult Page() => new PageResult();
///
/// Returns the file specified by () with the
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/PageResult.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/PageResult.cs
index 0529cf1be4..1f533b93fc 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/PageResult.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/PageResult.cs
@@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Mvc.RazorPages
@@ -13,26 +14,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
///
public class PageResult : ActionResult
{
- ///
- /// Initializes a new instance of .
- ///
- /// The to render.
- public PageResult(PageBase page)
- {
- Page = page;
- }
-
- ///
- /// Initializes a new instance of with the specified .
- ///
- /// The to render.
- /// The page model.
- public PageResult(PageBase page, object model)
- {
- Page = page;
- Model = model;
- }
-
///
/// Gets or sets the Content-Type header for the response.
///
@@ -41,12 +22,17 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
///
/// Gets the page model.
///
- public object Model { get; }
+ public object Model => ViewData?.Model;
///
- /// Gets the to execute.
+ /// Gets or sets the to be executed.
///
- public PageBase Page { get; }
+ public PageBase Page { get; set; }
+
+ ///
+ /// Gets or sets the for the page to be executed.
+ ///
+ public ViewDataDictionary ViewData { get; set; }
///
/// Gets or sets the HTTP status code.
@@ -56,14 +42,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
///
public override Task ExecuteResultAsync(ActionContext context)
{
- if (!object.ReferenceEquals(context, Page.PageContext))
+ if (!(context is PageContext pageContext))
{
- throw new ArgumentException(
- Resources.FormatPageViewResult_ContextIsInvalid(nameof(context), nameof(Page)));
+ throw new ArgumentException(Resources.FormatPageViewResult_ContextIsInvalid(
+ nameof(context),
+ nameof(Page),
+ nameof(PageResult)));
}
var executor = context.HttpContext.RequestServices.GetRequiredService();
- return executor.ExecuteAsync(Page.PageContext, this);
+ return executor.ExecuteAsync(pageContext, this);
}
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs
index cd6c6a8aa1..97366d9018 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs
@@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
=> string.Format(CultureInfo.CurrentCulture, GetString("ActivatedInstance_MustBeAnInstanceOf"), p0, p1);
///
- /// Argument '{0}' is not the same instance used to create '{1}'.
+ /// The context used to execute '{0}' must be an instance of '{1}'. Returning a '{2}' from a controller is a not supported.
///
internal static string PageViewResult_ContextIsInvalid
{
@@ -61,10 +61,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
}
///
- /// Argument '{0}' is not the same instance used to create '{1}'.
+ /// The context used to execute '{0}' must be an instance of '{1}'. Returning a '{2}' from a controller is a not supported.
///
- internal static string FormatPageViewResult_ContextIsInvalid(object p0, object p1)
- => string.Format(CultureInfo.CurrentCulture, GetString("PageViewResult_ContextIsInvalid"), p0, p1);
+ internal static string FormatPageViewResult_ContextIsInvalid(object p0, object p1, object p2)
+ => string.Format(CultureInfo.CurrentCulture, GetString("PageViewResult_ContextIsInvalid"), p0, p1, p2);
///
/// Value cannot be null or empty.
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx b/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx
index 2e8f00040c..dfcbcac906 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx
@@ -127,7 +127,7 @@
Page created by '{0}' must be an instance of '{1}'.
- Argument '{0}' is not the same instance used to create '{1}'.
+ The context used to execute '{0}' must be an instance of '{1}'. Returning a '{2}' from a controller is a not supported.
Value cannot be null or empty.
diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewDataDictionaryFactory.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewDataDictionaryFactory.cs
new file mode 100644
index 0000000000..7d08cc7125
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewDataDictionaryFactory.cs
@@ -0,0 +1,60 @@
+// 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.Diagnostics;
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+
+namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
+{
+ public static class ViewDataDictionaryFactory
+ {
+ public static Func CreateFactory(TypeInfo modelType)
+ {
+ if (modelType == null)
+ {
+ throw new ArgumentNullException(nameof(modelType));
+ }
+
+ var type = typeof(ViewDataDictionary<>).MakeGenericType(modelType);
+ var constructor = type.GetConstructor(new Type[] { typeof(IModelMetadataProvider), typeof(ModelStateDictionary) });
+ Debug.Assert(constructor != null);
+
+ var parameter1 = Expression.Parameter(typeof(IModelMetadataProvider), "metadataProvider");
+ var parameter2 = Expression.Parameter(typeof(ModelStateDictionary), "modelState");
+
+ return
+ Expression.Lambda>(
+ Expression.Convert(
+ Expression.New(constructor, parameter1, parameter2),
+ typeof(ViewDataDictionary)),
+ parameter1,
+ parameter2)
+ .Compile();
+ }
+
+ public static Func CreateNestedFactory(TypeInfo modelType)
+ {
+ if (modelType == null)
+ {
+ throw new ArgumentNullException(nameof(modelType));
+ }
+
+ var type = typeof(ViewDataDictionary<>).MakeGenericType(modelType);
+ var constructor = type.GetConstructor(new Type[] { typeof(ViewDataDictionary) });
+ Debug.Assert(constructor != null);
+
+ var parameter = Expression.Parameter(typeof(ViewDataDictionary), "viewDataDictionary");
+
+ return
+ Expression.Lambda>(
+ Expression.Convert(
+ Expression.New(constructor, parameter),
+ typeof(ViewDataDictionary)),
+ parameter)
+ .Compile();
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageActivatorTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageActivatorProviderTest.cs
similarity index 86%
rename from test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageActivatorTest.cs
rename to test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageActivatorProviderTest.cs
index 27b1da83c2..4276f81ae9 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageActivatorTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageActivatorProviderTest.cs
@@ -4,20 +4,21 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
- public class DefaultPageActivatorTest
+ public class DefaultPageActivatorProviderTest
{
[Fact]
public void CreateActivator_ThrowsIfPageTypeInfoIsNull()
{
// Arrange
var descriptor = new CompiledPageActionDescriptor();
- var activator = new DefaultPageActivator();
+ var activator = new DefaultPageActivatorProvider();
// Act & Assert
ExceptionAssert.ThrowsArgument(
@@ -33,16 +34,18 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
// Arrange
var pageContext = new PageContext();
+ var viewContext = new ViewContext();
var descriptor = new CompiledPageActionDescriptor
{
PageTypeInfo = type.GetTypeInfo(),
};
- var activator = new DefaultPageActivator();
+
+ var activator = new DefaultPageActivatorProvider();
// Act
var factory = activator.CreateActivator(descriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
Assert.NotNull(instance);
@@ -58,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
PageTypeInfo = typeof(PageWithoutParameterlessConstructor).GetTypeInfo(),
};
var pageContext = new PageContext();
- var activator = new DefaultPageActivator();
+ var activator = new DefaultPageActivatorProvider();
// Act & Assert
Assert.Throws(() => activator.CreateActivator(descriptor));
@@ -71,7 +74,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
// Arrange
var context = new PageContext();
- var activator = new DefaultPageActivator();
+ var activator = new DefaultPageActivatorProvider();
var page = new TestPage();
// Act
@@ -89,7 +92,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
// Arrange
var context = new PageContext();
- var activator = new DefaultPageActivator();
+ var viewContext = new ViewContext();
+ var activator = new DefaultPageActivatorProvider();
var page = new DisposablePage();
// Act & Assert
@@ -98,7 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
PageTypeInfo = page.GetType().GetTypeInfo()
});
Assert.NotNull(disposer);
- disposer(context, page);
+ disposer(context, viewContext, page);
// Assert
Assert.True(page.Disposed);
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageFactoryProviderTest.cs
similarity index 87%
rename from test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageFactoryTest.cs
rename to test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageFactoryProviderTest.cs
index 110c37a9b2..f0ccc4602d 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageFactoryTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageFactoryProviderTest.cs
@@ -53,11 +53,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
ActionDescriptor = descriptor
};
+ var viewContext = new ViewContext();
var factoryProvider = CreatePageFactory();
// Act
var factory = factoryProvider.CreatePageFactory(descriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
@@ -75,11 +76,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
PageTypeInfo = typeof(TestPage).GetTypeInfo(),
}
};
+
+ var viewContext = new ViewContext();
+
var urlHelperFactory = new Mock();
var urlHelper = Mock.Of();
- urlHelperFactory.Setup(f => f.GetUrlHelper(pageContext))
+ urlHelperFactory
+ .Setup(f => f.GetUrlHelper(viewContext))
.Returns(urlHelper)
.Verifiable();
+
var htmlEncoder = HtmlEncoder.Create();
var factoryProvider = CreatePageFactory(
@@ -88,7 +94,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
// Act
var factory = factoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
@@ -113,9 +119,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
ActionDescriptor = descriptor
};
+ var viewContext = new ViewContext();
+
// Act
var factory = CreatePageFactory().CreatePageFactory(descriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
@@ -135,11 +143,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
},
};
+ var viewContext = new ViewContext();
+
var factoryProvider = CreatePageFactory();
// Act
var factory = factoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
@@ -158,11 +168,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
},
};
+ var viewContext = new ViewContext();
+
var factoryProvider = CreatePageFactory();
// Act
var factory = factoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
@@ -170,7 +182,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
}
[Fact]
- public void PageFactorySetsNestedVidewDataDictionaryWhenContextHasANonNullDictionary()
+ public void PageFactory_SetsViewDataOnPage_FromPageContext()
{
// Arrange
var modelMetadataProvider = new EmptyModelMetadataProvider();
@@ -180,21 +192,28 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
PageTypeInfo = typeof(TestPage).GetTypeInfo()
},
- ViewData = new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary())
+ ViewData = new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary())
{
{ "test-key", "test-value" },
}
};
+ var viewContext = new ViewContext()
+ {
+ HttpContext = pageContext.HttpContext,
+ ViewData = pageContext.ViewData,
+ };
+
var factoryProvider = CreatePageFactory();
// Act
var factory = factoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
Assert.NotNull(testPage.ViewData);
+ Assert.Same(pageContext.ViewData, testPage.ViewData);
Assert.Equal("test-value", testPage.ViewData["test-key"]);
}
@@ -205,6 +224,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var serviceProvider = new ServiceCollection()
.AddSingleton(NullLogger.Instance)
.BuildServiceProvider();
+
var pageContext = new PageContext
{
ActionDescriptor = new CompiledPageActionDescriptor
@@ -215,14 +235,18 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
RequestServices = serviceProvider,
},
+ };
+ var viewContext = new ViewContext()
+ {
+ HttpContext = pageContext.HttpContext,
};
var factoryProvider = CreatePageFactory();
// Act
var factory = factoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
- var instance = factory(pageContext);
+ var instance = factory(pageContext, viewContext);
// Assert
var testPage = Assert.IsType(instance);
@@ -258,10 +282,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
private static IPageActivatorProvider CreateActivator()
{
var activator = new Mock();
- activator.Setup(a => a.CreateActivator(It.IsAny()))
+ activator
+ .Setup(a => a.CreateActivator(It.IsAny()))
.Returns((CompiledPageActionDescriptor descriptor) =>
{
- return (context) => Activator.CreateInstance(descriptor.PageTypeInfo.AsType());
+ return (context, viewContext) => Activator.CreateInstance(descriptor.PageTypeInfo.AsType());
});
return activator.Object;
}
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageModelActivatorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageModelActivatorProviderTest.cs
index 4e953e3dfe..e2e89e5214 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageModelActivatorProviderTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/DefaultPageModelActivatorProviderTest.cs
@@ -4,6 +4,7 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
@@ -95,7 +96,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
// Arrange
var context = new PageContext();
- var activator = new DefaultPageActivator();
+ var activator = new DefaultPageModelActivatorProvider();
var actionDescriptor = new CompiledPageActionDescriptor
{
PageTypeInfo = pageType.GetTypeInfo(),
@@ -113,11 +114,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
// Arrange
var context = new PageContext();
- var activator = new DefaultPageActivator();
+
+ var activator = new DefaultPageModelActivatorProvider();
var actionDescriptor = new CompiledPageActionDescriptor
{
- PageTypeInfo = typeof(DisposableModel).GetTypeInfo(),
+ ModelTypeInfo = typeof(DisposableModel).GetTypeInfo(),
};
+
var model = new DisposableModel();
// Act & Assert
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs
index 85dd34a504..eb96379878 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerProviderTest.cs
@@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
+using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Razor.Language;
@@ -38,8 +39,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
FilterDescriptors = new FilterDescriptor[0],
};
- Func factory = _ => null;
- Action releaser = (_, __) => { };
+ Func factory = (a, b) => null;
+ Action releaser = (a, b, c) => { };
var loader = new Mock();
loader
@@ -78,6 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Same(releaser, entry.ReleasePage);
Assert.Null(entry.ModelFactory);
Assert.Null(entry.ReleaseModel);
+ Assert.NotNull(entry.ViewDataFactory);
}
[Fact]
@@ -90,8 +92,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
FilterDescriptors = new FilterDescriptor[0],
};
- Func factory = _ => null;
- Action releaser = (_, __) => { };
+ Func factory = (a, b) => null;
+ Action releaser = (a, b, c) => { };
Func modelFactory = _ => null;
Action modelDisposer = (_, __) => { };
@@ -134,7 +136,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Assert
Assert.NotNull(context.Result);
+
var actionInvoker = Assert.IsType(context.Result);
+
var entry = actionInvoker.CacheEntry;
var compiledPageActionDescriptor = Assert.IsType(entry.ActionDescriptor);
Assert.Equal(descriptor.RelativePath, compiledPageActionDescriptor.RelativePath);
@@ -142,6 +146,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Same(releaser, entry.ReleasePage);
Assert.Same(modelFactory, entry.ModelFactory);
Assert.Same(modelDisposer, entry.ReleaseModel);
+ Assert.NotNull(entry.ViewDataFactory);
+
+ var pageContext = actionInvoker.PageContext;
+ Assert.Same(compiledPageActionDescriptor, pageContext.ActionDescriptor);
+ Assert.Same(context.ActionContext.HttpContext, pageContext.HttpContext);
+ Assert.Same(context.ActionContext.ModelState, pageContext.ModelState);
+ Assert.Same(context.ActionContext.RouteData, pageContext.RouteData);
+ Assert.Empty(pageContext.ValueProviderFactories);
+ Assert.NotNull(Assert.IsType>(pageContext.ViewData));
+ Assert.Empty(pageContext.ViewStartFactories);
}
[Fact]
@@ -476,16 +490,20 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
PageActionDescriptor descriptor,
Type pageType = null)
{
+ pageType = pageType ?? typeof(object);
+ var pageTypeInfo = pageType.GetTypeInfo();
+
TypeInfo modelTypeInfo = null;
if (pageType != null)
{
- modelTypeInfo = pageType.GetTypeInfo().GetProperty("Model")?.PropertyType.GetTypeInfo();
+ modelTypeInfo = pageTypeInfo.GetProperty("Model")?.PropertyType.GetTypeInfo();
}
return new CompiledPageActionDescriptor(descriptor)
{
- ModelTypeInfo = modelTypeInfo,
- PageTypeInfo = (pageType ?? typeof(object)).GetTypeInfo()
+ HandlerTypeInfo = modelTypeInfo ?? pageTypeInfo,
+ ModelTypeInfo = modelTypeInfo ?? pageTypeInfo,
+ PageTypeInfo = pageTypeInfo,
};
}
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs
index 045d99901d..7dbca6e257 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionInvokerTest.cs
@@ -14,8 +14,10 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
+using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -344,10 +346,18 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
.Verifiable();
var filter3 = new Mock(MockBehavior.Strict);
- var actionDescriptor = new CompiledPageActionDescriptor();
+
+ var actionDescriptor = new CompiledPageActionDescriptor()
+ {
+ HandlerTypeInfo = typeof(TestPage).GetTypeInfo(),
+ ModelTypeInfo = typeof(TestPage).GetTypeInfo(),
+ PageTypeInfo = typeof(TestPage).GetTypeInfo(),
+ };
+
var cacheEntry = new PageActionInvokerCacheEntry(
actionDescriptor,
- (context) => createCalled = true,
+ null,
+ (context, viewContext) => createCalled = true,
null,
(context) => null,
null,
@@ -400,10 +410,17 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var filter3 = new Mock(MockBehavior.Strict);
- var actionDescriptor = new CompiledPageActionDescriptor();
+ var actionDescriptor = new CompiledPageActionDescriptor()
+ {
+ HandlerTypeInfo = typeof(TestPage).GetTypeInfo(),
+ ModelTypeInfo = typeof(TestPage).GetTypeInfo(),
+ PageTypeInfo = typeof(TestPage).GetTypeInfo(),
+ };
+
var cacheEntry = new PageActionInvokerCacheEntry(
actionDescriptor,
- (context) => createCalled = true,
+ null,
+ (context, viewContext) => createCalled = true,
null,
(context) => null,
null,
@@ -540,6 +557,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
PageResultExecutor executor = null,
IPageHandlerMethodSelector selector = null,
PageActionInvokerCacheEntry cacheEntry = null,
+ ITempDataDictionaryFactory tempDataFactory = null,
int maxAllowedErrorsInModelState = 200,
List valueProviderFactories = null,
RouteData routeData = null,
@@ -572,15 +590,14 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
httpContext: httpContext,
routeData: routeData,
actionDescriptor: actionDescriptor);
- var pageContext = new PageContext(
- actionContext,
- new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()),
- Mock.Of(),
- new HtmlHelperOptions())
+ var pageContext = new PageContext(actionContext)
{
- ActionDescriptor = actionDescriptor
+ ActionDescriptor = actionDescriptor,
};
+ var viewDataFactory = ViewDataDictionaryFactory.CreateFactory(actionDescriptor.ModelTypeInfo);
+ pageContext.ViewData = viewDataFactory(new EmptyModelMetadataProvider(), pageContext.ModelState);
+
if (selector == null)
{
selector = Mock.Of();
@@ -596,7 +613,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
logger = NullLogger.Instance;
}
- Func pageFactory = (context) =>
+ if (tempDataFactory == null)
+ {
+ tempDataFactory = Mock.Of(m => m.GetTempData(It.IsAny()) == Mock.Of());
+ }
+
+ Func pageFactory = (context, viewContext) =>
{
var instance = (Page)Activator.CreateInstance(actionDescriptor.PageTypeInfo.AsType());
instance.PageContext = context;
@@ -605,8 +627,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
cacheEntry = new PageActionInvokerCacheEntry(
actionDescriptor,
+ viewDataFactory,
pageFactory,
- (c, page) => { (page as IDisposable)?.Dispose(); },
+ (c, viewContext, page) => { (page as IDisposable)?.Dispose(); },
_ => Activator.CreateInstance(actionDescriptor.ModelTypeInfo.AsType()),
(c, model) => { (model as IDisposable)?.Dispose(); },
null,
@@ -622,7 +645,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
filters,
valueProviderFactories.AsReadOnly(),
cacheEntry,
- GetParameterBinder());
+ GetParameterBinder(),
+ tempDataFactory,
+ new HtmlHelperOptions());
return invoker;
}
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PagePropertyBinderFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PagePropertyBinderFactoryTest.cs
index 618385a4f3..771e32de1f 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PagePropertyBinderFactoryTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PagePropertyBinderFactoryTest.cs
@@ -199,7 +199,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
};
// Act
- await factory(page, null);
+ await factory(page.PageContext, page);
// Assert
Assert.Equal(10, page.Id);
@@ -262,7 +262,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var model = new PageModelWithProperty();
// Act
- await factory(page, model);
+ await factory(page.PageContext, model);
// Assert
// Verify that the page properties were not bound.
@@ -314,7 +314,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var defaultValue = model.PropertyWithDefaultValue;
// Act
- await factory(page, model);
+ await factory(page.PageContext, model);
// Assert
Assert.Equal(defaultValue, model.PropertyWithDefaultValue);
@@ -375,7 +375,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var model = new PageModelWithSupportsGetProperty();
// Act
- await factory(page, model);
+ await factory(page.PageContext, model);
// Assert
Assert.Equal("value", model.SupportsGet);
@@ -434,7 +434,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var model = new PageModelWithSupportsGetProperty();
// Act
- await factory(page, model);
+ await factory(page.PageContext, model);
// Assert
Assert.Equal("value", model.SupportsGet);
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs
index db34bff3b6..9346bfe5c3 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs
@@ -1406,15 +1406,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
- var viewDataDictionary = new ViewDataDictionary(modelMetadataProvider, modelState);
- var tempData = Mock.Of();
- var pageContext = new PageContext(actionContext, viewDataDictionary, tempData, new HtmlHelperOptions());
+ var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
+ var pageContext = new PageContext(actionContext)
+ {
+ ViewData = viewData,
+ };
var page = new TestPage
{
PageContext = pageContext,
};
- pageContext.Page = page;
var pageModel = new TestPageModel
{
@@ -1423,13 +1424,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
// Act & Assert
Assert.Same(pageContext, pageModel.PageContext);
- Assert.Same(pageContext, pageModel.ViewContext);
Assert.Same(httpContext, pageModel.HttpContext);
Assert.Same(httpContext.Request, pageModel.Request);
Assert.Same(httpContext.Response, pageModel.Response);
Assert.Same(modelState, pageModel.ModelState);
- Assert.Same(viewDataDictionary, pageModel.ViewData);
- Assert.Same(tempData, pageModel.TempData);
+ Assert.Same(viewData, pageModel.ViewData);
}
[Fact]
@@ -1483,10 +1482,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
var page = new TestPage();
var pageModel = new TestPageModel
{
- PageContext = new PageContext
- {
- Page = page,
- }
+ PageContext = new PageContext()
};
// Act
@@ -1494,7 +1490,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
// Assert
var pageResult = Assert.IsType(result);
- Assert.Same(page, pageResult.Page);
+ Assert.Null(pageResult.Page); // This is set by the invoker
}
private class ContentPageModel : PageModel
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs
index 50d92356b2..d8fa42deb6 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs
@@ -9,8 +9,10 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Moq;
@@ -28,17 +30,24 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
- var viewDataDictionary = new ViewDataDictionary(modelMetadataProvider, modelState);
+ var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var tempData = Mock.Of();
- var pageContext = new PageContext(actionContext, viewDataDictionary, tempData, new HtmlHelperOptions());
+
+ var pageContext = new PageContext(actionContext)
+ {
+ ViewData = viewData,
+ };
+ var viewContext = new ViewContext(pageContext, NullView.Instance, viewData, tempData, TextWriter.Null, new HtmlHelperOptions());
var page = new TestPage
{
PageContext = pageContext,
+ ViewContext = viewContext,
};
// Act & Assert
- Assert.Same(pageContext, page.ViewContext);
+ Assert.Same(pageContext, page.PageContext);
+ Assert.Same(viewContext, page.ViewContext);
Assert.Same(httpContext, page.HttpContext);
Assert.Same(httpContext.Request, page.Request);
Assert.Same(httpContext.Response, page.Response);
diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs
index ecea4a4320..8f04bc0984 100644
--- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/SaveTempDataFilter/PageSaveTempDataPropertyFilterTest.cs
@@ -3,11 +3,13 @@
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;
@@ -164,7 +166,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
var testProp = pageType.GetProperty(nameof(TestPageString.Test));
var test2Prop = pageType.GetProperty(nameof(TestPageString.Test2));
- provider.TempDataProperties = new List {
+ provider.TempDataProperties = new List
+ {
new TempDataProperty(testProp, testProp.GetValue, testProp.SetValue),
new TempDataProperty(test2Prop, test2Prop.GetValue, test2Prop.SetValue)
};
@@ -177,15 +180,17 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
Assert.Null(page.Test2);
}
- private static PageContext CreateViewContext(HttpContext httpContext, ITempDataDictionary tempData)
+ 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 PageContext(
+ var viewContext = new ViewContext(
actionContext,
+ NullView.Instance,
viewData,
tempData,
+ TextWriter.Null,
new HtmlHelperOptions());
return viewContext;