[Fixes #7373] Assigning to the context's Result property, when implementing IPageFilter, causes an exception
This commit is contained in:
parent
bfbd286ab6
commit
d5e044f693
|
|
@ -21,6 +21,7 @@
|
|||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
|
||||
<li><a asp-page="/PagesHome">PagesHome</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
|
||||
protected abstract Task InvokeInnerFilterAsync();
|
||||
|
||||
protected async Task InvokeResultAsync(IActionResult result)
|
||||
protected virtual async Task InvokeResultAsync(IActionResult result)
|
||||
{
|
||||
var actionContext = _actionContext;
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,36 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
}
|
||||
}
|
||||
|
||||
protected override Task InvokeResultAsync(IActionResult result)
|
||||
{
|
||||
// We also have some special initialization we need to do for PageResult.
|
||||
if (result is PageResult pageResult)
|
||||
{
|
||||
// If we used a PageModel then the Page isn't initialized yet.
|
||||
if (_viewContext == null)
|
||||
{
|
||||
_viewContext = new ViewContext(
|
||||
_pageContext,
|
||||
NullView.Instance,
|
||||
_pageContext.ViewData,
|
||||
_tempDataFactory.GetTempData(_pageContext.HttpContext),
|
||||
TextWriter.Null,
|
||||
_htmlHelperOptions);
|
||||
_viewContext.ExecutingFilePath = _pageContext.ActionDescriptor.RelativePath;
|
||||
}
|
||||
|
||||
if (_page == null)
|
||||
{
|
||||
_page = (PageBase)CacheEntry.PageFactory(_pageContext, _viewContext);
|
||||
}
|
||||
|
||||
pageResult.Page = _page;
|
||||
pageResult.ViewData = pageResult.ViewData ?? _pageContext.ViewData;
|
||||
}
|
||||
|
||||
return base.InvokeResultAsync(result);
|
||||
}
|
||||
|
||||
private object CreateInstance()
|
||||
{
|
||||
if (HasPageModel)
|
||||
|
|
@ -248,31 +278,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
{
|
||||
_result = new PageResult();
|
||||
}
|
||||
|
||||
// We also have some special initialization we need to do for PageResult.
|
||||
if (_result is PageResult pageResult)
|
||||
{
|
||||
// If we used a PageModel then the Page isn't initialized yet.
|
||||
if (_viewContext == null)
|
||||
{
|
||||
_viewContext = new ViewContext(
|
||||
_pageContext,
|
||||
NullView.Instance,
|
||||
_pageContext.ViewData,
|
||||
_tempDataFactory.GetTempData(_pageContext.HttpContext),
|
||||
TextWriter.Null,
|
||||
_htmlHelperOptions);
|
||||
_viewContext.ExecutingFilePath = _pageContext.ActionDescriptor.RelativePath;
|
||||
}
|
||||
|
||||
if (_page == null)
|
||||
{
|
||||
_page = (PageBase)CacheEntry.PageFactory(_pageContext, _viewContext);
|
||||
}
|
||||
|
||||
pageResult.Page = _page;
|
||||
pageResult.ViewData = pageResult.ViewData ?? _pageContext.ViewData;
|
||||
}
|
||||
}
|
||||
|
||||
private Task Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ using System.Net.Http.Headers;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -1269,6 +1271,30 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore.InjectedPa
|
|||
Assert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(IAuthorizationFilter.OnAuthorization))]
|
||||
[InlineData(nameof(IAsyncAuthorizationFilter.OnAuthorizationAsync))]
|
||||
public async Task PageResultSetAt_AuthorizationFilter_Works(string targetName)
|
||||
{
|
||||
// Act
|
||||
var content = await Client.GetStringAsync("http://localhost/Pages/ShortCircuitPageAtAuthFilter?target=" + targetName);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("From ShortCircuitPageAtAuthFilter.cshtml", content);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(IPageFilter.OnPageHandlerExecuting))]
|
||||
[InlineData(nameof(IAsyncPageFilter.OnPageHandlerExecutionAsync))]
|
||||
public async Task PageResultSetAt_PageFilter_Works(string targetName)
|
||||
{
|
||||
// Act
|
||||
var content = await Client.GetStringAsync("http://localhost/Pages/ShortCircuitPageAtPageFilter?target=" + targetName);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("From ShortCircuitPageAtPageFilter.cshtml", content);
|
||||
}
|
||||
|
||||
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)
|
||||
{
|
||||
var getResponse = await Client.GetAsync(request.RequestUri);
|
||||
|
|
|
|||
|
|
@ -432,7 +432,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
.Verifiable();
|
||||
filter1
|
||||
.Setup(f => f.OnPageHandlerExecutionAsync(It.IsAny<PageHandlerExecutingContext>(), It.IsAny<PageHandlerExecutionDelegate>()))
|
||||
.Returns<PageHandlerExecutingContext, PageHandlerExecutionDelegate>(async(c, next) =>
|
||||
.Returns<PageHandlerExecutingContext, PageHandlerExecutionDelegate>(async (c, next) =>
|
||||
{
|
||||
Assert.Same(handler, c.HandlerMethod);
|
||||
await next();
|
||||
|
|
@ -529,6 +529,284 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Assert.Same(Result, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_AsyncAuthorizeFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IAsyncAuthorizationFilter>(MockBehavior.Strict);
|
||||
filter
|
||||
.Setup(f => f.OnAuthorizationAsync(It.IsAny<AuthorizationFilterContext>()))
|
||||
.Returns<AuthorizationFilterContext>((context) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
return Task.CompletedTask;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnAuthorizationAsync(It.IsAny<AuthorizationFilterContext>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_SyncAuthorizeFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IAuthorizationFilter>(MockBehavior.Strict);
|
||||
filter
|
||||
.Setup(f => f.OnAuthorization(It.IsAny<AuthorizationFilterContext>()))
|
||||
.Callback<AuthorizationFilterContext>((context) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnAuthorization(It.IsAny<AuthorizationFilterContext>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_AsyncResourceFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IAsyncResourceFilter>(MockBehavior.Strict);
|
||||
filter
|
||||
.Setup(f => f.OnResourceExecutionAsync(It.IsAny<ResourceExecutingContext>(), It.IsAny<ResourceExecutionDelegate>()))
|
||||
.Returns<ResourceExecutingContext, ResourceExecutionDelegate>((context, next) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
return Task.CompletedTask;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnResourceExecutionAsync(It.IsAny<ResourceExecutingContext>(), It.IsAny<ResourceExecutionDelegate>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_SyncResourceFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IResourceFilter>(MockBehavior.Strict);
|
||||
filter
|
||||
.Setup(f => f.OnResourceExecuting(It.IsAny<ResourceExecutingContext>()))
|
||||
.Callback<ResourceExecutingContext>((context) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnResourceExecuting(It.IsAny<ResourceExecutingContext>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_AsyncResultFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IAsyncResultFilter>(MockBehavior.Strict);
|
||||
filter
|
||||
.Setup(f => f.OnResultExecutionAsync(It.IsAny<ResultExecutingContext>(), It.IsAny<ResultExecutionDelegate>()))
|
||||
.Returns<ResultExecutingContext, ResultExecutionDelegate>((context, next) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
return next();
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnResultExecutionAsync(It.IsAny<ResultExecutingContext>(), It.IsAny<ResultExecutionDelegate>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_SyncResultFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IResultFilter>();
|
||||
filter
|
||||
.Setup(f => f.OnResultExecuting(It.IsAny<ResultExecutingContext>()))
|
||||
.Callback<ResultExecutingContext>((context) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnResultExecuting(It.IsAny<ResultExecutingContext>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_AsyncPageFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IAsyncPageFilter>(MockBehavior.Strict);
|
||||
AllowSelector(filter);
|
||||
filter
|
||||
.Setup(f => f.OnPageHandlerExecutionAsync(It.IsAny<PageHandlerExecutingContext>(), It.IsAny<PageHandlerExecutionDelegate>()))
|
||||
.Returns<PageHandlerExecutingContext, PageHandlerExecutionDelegate>((context, next) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
return Task.CompletedTask;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnPageHandlerExecutionAsync(It.IsAny<PageHandlerExecutingContext>(), It.IsAny<PageHandlerExecutionDelegate>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_PageResultSetAt_SyncPageFilter_PopulatesProperties()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResult = new PageResult();
|
||||
|
||||
IActionResult result = null;
|
||||
var filter = new Mock<IPageFilter>(MockBehavior.Strict);
|
||||
AllowSelector(filter);
|
||||
filter
|
||||
.Setup(f => f.OnPageHandlerExecuting(It.IsAny<PageHandlerExecutingContext>()))
|
||||
.Callback<PageHandlerExecutingContext>((context) =>
|
||||
{
|
||||
context.Result = expectedResult;
|
||||
result = context.Result;
|
||||
})
|
||||
.Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(filter.Object);
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
||||
// Assert
|
||||
filter.Verify(
|
||||
f => f.OnPageHandlerExecuting(It.IsAny<PageHandlerExecutingContext>()),
|
||||
Times.Once());
|
||||
|
||||
var pageResult = Assert.IsType<PageResult>(result);
|
||||
Assert.Same(expectedResult, pageResult);
|
||||
Assert.NotNull(pageResult.Page);
|
||||
Assert.NotNull(pageResult.ViewData);
|
||||
Assert.NotNull(pageResult.Page.ViewContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_InvokesPageFilter_ShortCircuit()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
@page
|
||||
@model ShortCircuitAtAuthFilterPageModel
|
||||
@{
|
||||
}
|
||||
From ShortCircuitPageAtAuthFilter.cshtml
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace RazorPagesWebSite.Pages
|
||||
{
|
||||
[AsyncTestAuthorizationFilter]
|
||||
[SyncTestAuthorizationFilter]
|
||||
public class ShortCircuitAtAuthFilterPageModel : PageModel
|
||||
{
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
private static bool ShouldShortCircuit(HttpContext httpContext, string currentTargetName)
|
||||
{
|
||||
return httpContext.Request.Query.TryGetValue("target", out var expectedTargetName)
|
||||
&& string.Equals(expectedTargetName, currentTargetName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private class AsyncTestAuthorizationFilterAttribute : Attribute, IAsyncAuthorizationFilter
|
||||
{
|
||||
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
if (ShouldShortCircuit(context.HttpContext, nameof(OnAuthorizationAsync)))
|
||||
{
|
||||
context.Result = new PageResult();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private class SyncTestAuthorizationFilterAttribute : Attribute, IAuthorizationFilter
|
||||
{
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
if (ShouldShortCircuit(context.HttpContext, nameof(OnAuthorization)))
|
||||
{
|
||||
context.Result = new PageResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@page
|
||||
@model ShortCircuitAtPageFilterPageModel
|
||||
@{
|
||||
}
|
||||
From ShortCircuitPageAtPageFilter.cshtml
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace RazorPagesWebSite.Pages
|
||||
{
|
||||
[AsyncTestPageFilter]
|
||||
[SyncTestPageFilter]
|
||||
public class ShortCircuitAtPageFilterPageModel : PageModel
|
||||
{
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
private static bool ShouldShortCircuit(HttpContext httpContext, string currentTargetName)
|
||||
{
|
||||
return httpContext.Request.Query.TryGetValue("target", out var expectedTargetName)
|
||||
&& string.Equals(expectedTargetName, currentTargetName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private class AsyncTestPageFilterAttribute : Attribute, IAsyncPageFilter
|
||||
{
|
||||
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnPageHandlerExecutionAsync(
|
||||
PageHandlerExecutingContext context,
|
||||
PageHandlerExecutionDelegate next)
|
||||
{
|
||||
if (ShouldShortCircuit(context.HttpContext, nameof(OnPageHandlerExecutionAsync)))
|
||||
{
|
||||
context.Result = new PageResult();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
private class SyncTestPageFilterAttribute : Attribute, IPageFilter
|
||||
{
|
||||
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
|
||||
{
|
||||
if (ShouldShortCircuit(context.HttpContext, nameof(OnPageHandlerExecuting)))
|
||||
{
|
||||
context.Result = new PageResult();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue