[Fixes #7373] Assigning to the context's Result property, when implementing IPageFilter, causes an exception

This commit is contained in:
Kiran Challa 2018-04-12 05:39:58 -07:00
parent bfbd286ab6
commit d5e044f693
9 changed files with 465 additions and 27 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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()
{

View File

@ -0,0 +1,5 @@
@page
@model ShortCircuitAtAuthFilterPageModel
@{
}
From ShortCircuitPageAtAuthFilter.cshtml

View File

@ -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();
}
}
}
}
}

View File

@ -0,0 +1,5 @@
@page
@model ShortCircuitAtPageFilterPageModel
@{
}
From ShortCircuitPageAtPageFilter.cshtml

View File

@ -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)
{
}
}
}
}