Merge pull request #8553 from dotnet-maestro-bot/merge/release/2.2-to-master

[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
Doug Bunting 2018-10-04 16:23:43 -07:00 committed by GitHub
commit 72e93d82ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 450 additions and 70 deletions

1
.gitignore vendored
View File

@ -37,7 +37,6 @@ node_modules
*launchSettings.json
*.orig
.vscode/
global.json
BenchmarkDotNet.Artifacts/
.idea/
msbuild.binlog

View File

@ -2,6 +2,11 @@
<configuration>
<packageSources>
<clear />
<!-- Restore sources should be defined in build/sources.props. -->
<!--
Restore sources should be defined in build/sources.props.
The only allowed feed here is myget.org/aspnet-tools which is required to work around
https://github.com/Microsoft/msbuild/issues/2914
-->
<add key="myget.org aspnetcore-tools" value="https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json" />
</packageSources>
</configuration>

View File

@ -17,7 +17,6 @@
<BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>2.1.1.1</BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>
<BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>2.1.1</BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>
<InternalAspNetCoreAnalyzersPackageVersion>3.0.0-alpha1-10549</InternalAspNetCoreAnalyzersPackageVersion>
<InternalAspNetCoreSdkPackageVersion>3.0.0-alpha1-20180919.1</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAllPackageVersion>3.0.0-alpha1-10549</MicrosoftAspNetCoreAllPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>3.0.0-alpha1-10549</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>3.0.0-alpha1-10549</MicrosoftAspNetCoreAntiforgeryPackageVersion>

8
global.json Normal file
View File

@ -0,0 +1,8 @@
{
"sdk": {
"version": "2.2.100-preview2-009404"
},
"msbuild-sdks": {
"Internal.AspNetCore.Sdk": "2.2.0-preview2-20181003.2"
}
}

View File

@ -1,2 +1,2 @@
version:3.0.0-alpha1-20180919.1
commithash:3066ae0a230870ea07e3f132605b5e5493f8bbd4
version:3.0.0-alpha1-20181004.5
commithash:8725f7194e9976f75f90f56afc0fba6116ac597c

View File

@ -2,7 +2,6 @@
<Import Project="..\Directory.Build.props" />
<ItemGroup>
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
<PackageReference Include="Internal.AspNetCore.Analyzers" PrivateAssets="All" Version="$(InternalAspNetCoreAnalyzersPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC abstractions and interfaces for action invocation and dispatching, authorization, action filters, formatters, model binding, routing, validation, and more.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>CSharp Analyzers for ASP.NET Core MVC.</Description>
<PackageTags>aspnetcore;aspnetcoremvc</PackageTags>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>CSharp Analyzers for ASP.NET Core MVC.</Description>
<PackageTags>aspnetcore;aspnetcoremvc</PackageTags>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC API explorer functionality for discovering metadata such as the list of controllers and actions, and their URLs and allowed HTTP methods.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC core components. Contains common action result types, attribute routing, application model conventions, API explorer, application parts, filters, formatters, model binding, and more.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC cross-origin resource sharing (CORS) features.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC metadata and validation system using System.ComponentModel.DataAnnotations.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC formatters for JSON input and output and for JSON PATCH input using Json.NET.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC formatters for XML input and output using DataContractSerializer and XmlSerializer.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC features that enable globalization and localization of applications.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC Razor view engine for CSHTML files.</Description>

View File

@ -3,36 +3,43 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Options;
using Resources = Microsoft.AspNetCore.Mvc.RazorPages.Resources;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
public class DefaultPageApplicationModelProvider : IPageApplicationModelProvider
internal class DefaultPageApplicationModelProvider : IPageApplicationModelProvider
{
private const string ModelPropertyName = "Model";
private readonly PageHandlerPageFilter _pageHandlerPageFilter = new PageHandlerPageFilter();
private readonly PageHandlerResultFilter _pageHandlerResultFilter = new PageHandlerResultFilter();
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly MvcOptions _options;
private readonly MvcOptions _mvcOptions;
private readonly RazorPagesOptions _razorPagesOptions;
private readonly Func<ActionContext, bool> _supportsAllRequests;
private readonly Func<ActionContext, bool> _supportsNonGetRequests;
private readonly HandleOptionsRequestsPageFilter _handleOptionsRequestsFilter;
public DefaultPageApplicationModelProvider(
IModelMetadataProvider modelMetadataProvider,
IOptions<MvcOptions> options)
IOptions<MvcOptions> options,
IOptions<RazorPagesOptions> razorPagesOptions)
{
_modelMetadataProvider = modelMetadataProvider;
_options = options.Value;
_mvcOptions = options.Value;
_razorPagesOptions = razorPagesOptions.Value;
_supportsAllRequests = _ => true;
_supportsNonGetRequests = context => !string.Equals(context.HttpContext.Request.Method, "GET", StringComparison.OrdinalIgnoreCase);
_supportsNonGetRequests = context => !HttpMethods.IsGet(context.HttpContext.Request.Method);
_handleOptionsRequestsFilter = new HandleOptionsRequestsPageFilter();
}
/// <inheritdoc />
@ -175,6 +182,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
pageModel.Filters.Add(_pageHandlerResultFilter);
}
if (_razorPagesOptions.AllowDefaultHandlingForOptionsRequests)
{
pageModel.Filters.Add(_handleOptionsRequestsFilter);
}
}
/// <summary>
@ -237,7 +249,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var attributes = parameter.GetCustomAttributes(inherit: true);
BindingInfo bindingInfo;
if (_options.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
if (_mvcOptions.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
{
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);

View File

@ -0,0 +1,55 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
/// <summary>
/// A filter that handles OPTIONS requests page when no handler method is available.
/// <para>
/// a) MVC treats no handler being selected no differently than a page having no handler, both execute the
/// page.
/// b) A common model for programming Razor Pages is to initialize content required by a page in the
/// <c>OnGet</c> handler. Executing a page without running the handler may result in runtime exceptions -
/// e.g. null ref or out of bounds exception if you expected a property or collection to be initialized.
/// </para>
/// <para>
/// Some web crawlers use OPTIONS request when probing servers. In the absence of an uncommon <c>OnOptions</c>
/// handler, executing the page will likely result in runtime errors as described in earlier. This filter
/// attempts to avoid this pit of failure by handling OPTIONS requests and returning a 200 if no handler is selected.
/// </para>
/// </summary>
internal sealed class HandleOptionsRequestsPageFilter : IPageFilter, IOrderedFilter
{
/// <summary>
/// Ordered to run after filters with default order.
/// </summary>
public int Order => 1000;
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.HandlerMethod == null &&
context.Result == null &&
HttpMethods.IsOptions(context.HttpContext.Request.Method))
{
context.Result = new OkResult();
}
}
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
}
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC Razor Pages.</Description>

View File

@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
{
private readonly CompatibilitySwitch<bool> _allowAreas;
private readonly CompatibilitySwitch<bool> _allowMappingHeadRequestsToGetHandler;
private readonly CompatibilitySwitch<bool> _allowsDefaultHandlingForOptionsRequests;
private readonly ICompatibilitySwitch[] _switches;
private string _root = "/Pages";
@ -24,11 +25,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
{
_allowAreas = new CompatibilitySwitch<bool>(nameof(AllowAreas));
_allowMappingHeadRequestsToGetHandler = new CompatibilitySwitch<bool>(nameof(AllowMappingHeadRequestsToGetHandler));
_allowsDefaultHandlingForOptionsRequests = new CompatibilitySwitch<bool>(nameof(AllowDefaultHandlingForOptionsRequests));
_switches = new ICompatibilitySwitch[]
{
_allowAreas,
_allowMappingHeadRequestsToGetHandler,
_allowsDefaultHandlingForOptionsRequests,
};
}
@ -134,6 +137,45 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
set => _allowMappingHeadRequestsToGetHandler.Value = value;
}
/// <summary>
/// Gets or sets a value that determines if HTTP requests with the OPTIONS method are handled by default, if
/// no handler is available.
/// </summary>
/// <value>
/// The default value is <see langword="true"/> if the version is
/// <see cref="CompatibilityVersion.Version_2_2"/> or later; <see langword="false"/> otherwise.
/// </value>
/// <remarks>
/// <para>
/// Razor Pages uses the current request's HTTP method to select a handler method. When no handler is available or selected,
/// the page is immediately executed. This may cause runtime errors if the page relies on the handler method to execute
/// and initialize some state. This setting attempts to avoid this class of error for HTTP <c>OPTIONS</c> requests by
/// returning a <c>200 OK</c> response.
/// </para>
/// <para>
/// This property is associated with a compatibility switch and can provide a different behavior depending on
/// the configured compatibility version for the application. See <see cref="CompatibilityVersion"/> for
/// guidance and examples of setting the application's compatibility version.
/// </para>
/// <para>
/// Configuring the desired of the value compatibility switch by calling this property's setter will take precedence
/// over the value implied by the application's <see cref="CompatibilityVersion"/>.
/// </para>
/// <para>
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_2"/> then
/// this setting will have value <c>true</c> unless explicitly configured.
/// </para>
/// <para>
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
/// lower then this setting will have value <c>true</c> unless explicitly configured.
/// </para>
/// </remarks>
public bool AllowDefaultHandlingForOptionsRequests
{
get => _allowsDefaultHandlingForOptionsRequests.Value;
set => _allowsDefaultHandlingForOptionsRequests.Value = value;
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
{
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();

View File

@ -29,6 +29,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
values[nameof(RazorPagesOptions.AllowMappingHeadRequestsToGetHandler)] = true;
}
if (Version >= CompatibilityVersion.Version_2_2)
{
values[nameof(RazorPagesOptions.AllowDefaultHandlingForOptionsRequests)] = true;
}
return values;
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC default tag helpers. Contains tag helpers for anchor tags, HTML input elements, caching, scripts, links (for CSS), and more.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>Support for writing functional tests for MVC applications.</Description>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC view rendering features. Contains common types used in most MVC applications as well as view rendering features such as view engines, views, view components, and HTML helpers.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>Provides compatibility in ASP.NET Core MVC with ASP.NET Web API 2 to simplify migration of existing Web API implementations.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC is a web framework that gives you a powerful, patterns-based way to build dynamic websites and web APIs. ASP.NET Core MVC enables a clean separation of concerns and gives you full control over markup.</Description>

View File

@ -14,7 +14,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<Import Project="..\..\src\Microsoft.AspNetCore.Mvc.Testing\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Testing.targets" />
<PropertyGroup>

View File

@ -1431,6 +1431,54 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore.InjectedPa
Assert.Equal("ViewData: Bar", content);
}
[Fact]
public async Task OptionsRequest_WithoutHandler_Returns200_WithoutExecutingPage()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/HelloWorld");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content.Trim());
}
[Fact]
public async Task PageWithOptionsHandler_ExecutesGetRequest()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/HelloWorldWithOptionsHandler");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("Hello from OnGet!", content.Trim());
}
[Fact]
public async Task PageWithOptionsHandler_ExecutesOptionsRequest()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/HelloWorldWithOptionsHandler");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("Hello from OnOptions!", content.Trim());
}
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)
{
var getResponse = await Client.GetAsync(request.RequestUri);

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -6,15 +6,16 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
using Microsoft.Extensions.Options;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
public class DefaultPageApplicationModelProviderTest
{
@ -887,7 +888,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Arrange
var provider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = false }));
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = false }),
Options.Create(new RazorPagesOptions()));
var typeInfo = typeof(PageWithHandlerParameters).GetTypeInfo();
var expected = typeInfo.GetMethod(nameof(PageWithHandlerParameters.OnPost));
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -921,11 +923,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnPost(string name, [ModelBinder(Name = "personId")] int id) { }
}
// We're using PropertyHelper from Common to find the properties here, which implements
// We're using PropertyHelper from Common to find the properties here, which implements
// out standard set of semantics for properties that the framework interacts with.
//
// One of the desirable consequences of that is we only find 'visible' properties. We're not
// retesting all of the details of PropertyHelper here, just the visibility part as a quick check
//
// One of the desirable consequences of that is we only find 'visible' properties. We're not
// retesting all of the details of PropertyHelper here, just the visibility part as a quick check
// that we're using PropertyHelper as expected.
[Fact]
public void PopulateHandlerProperties_UsesPropertyHelpers_ToFindProperties()
@ -1071,6 +1073,41 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnGetUser() { }
}
[Fact]
public void PopulateFilters_With21CompatBehavior_DoesNotAddDisallowOptionsRequestsPageFilter()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions()),
Options.Create(new RazorPagesOptions()));
var typeInfo = typeof(object).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
// Act
provider.PopulateFilters(pageModel);
// Assert
Assert.Empty(pageModel.Filters);
}
[Fact]
public void PopulateFilters_AddsDisallowOptionsRequestsPageFilter()
{
// Arrange
var provider = CreateProvider();
var typeInfo = typeof(object).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
// Act
provider.PopulateFilters(pageModel);
// Assert
Assert.Collection(
pageModel.Filters,
filter => Assert.IsType<HandleOptionsRequestsPageFilter>(filter));
}
[Fact]
public void PopulateFilters_AddsIFilterMetadataAttributesToModel()
{
@ -1085,7 +1122,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Assert
Assert.Collection(
pageModel.Filters,
filter => Assert.IsType<TypeFilterAttribute>(filter));
filter => Assert.IsType<TypeFilterAttribute>(filter),
filter => Assert.IsType<HandleOptionsRequestsPageFilter>(filter));
}
[PageModel]
@ -1109,7 +1147,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Assert
Assert.Collection(
pageModel.Filters,
filter => Assert.IsType<PageHandlerPageFilter>(filter));
filter => Assert.IsType<PageHandlerPageFilter>(filter),
filter => Assert.IsType<HandleOptionsRequestsPageFilter>(filter));
}
private class ModelImplementingAsyncPageFilter : IAsyncPageFilter
@ -1139,7 +1178,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Assert
Assert.Collection(
pageModel.Filters,
filter => Assert.IsType<PageHandlerPageFilter>(filter));
filter => Assert.IsType<PageHandlerPageFilter>(filter),
filter => Assert.IsType<HandleOptionsRequestsPageFilter>(filter));
}
private class ModelImplementingPageFilter : IPageFilter
@ -1175,7 +1215,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Collection(
pageModel.Filters,
filter => Assert.IsType<ServiceFilterAttribute>(filter),
filter => Assert.IsType<PageHandlerPageFilter>(filter));
filter => Assert.IsType<PageHandlerPageFilter>(filter),
filter => Assert.IsType<HandleOptionsRequestsPageFilter>(filter));
}
[ServiceFilter(typeof(IServiceProvider))]
@ -1185,7 +1226,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
return new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }));
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }),
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
}
}
}

View File

@ -0,0 +1,135 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
public class DisallowOptionsRequestsPageFilterTest
{
[Fact]
public void OnPageHandlerExecuting_DoesNothing_IfHandlerIsSelected()
{
// Arrange
var context = GetContext(new HandlerMethodDescriptor());
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.Null(context.Result);
}
[Fact]
public void OnPageHandlerExecuting_DoesNotOverwriteResult_IfHandlerIsSelected()
{
// Arrange
var expected = new PageResult();
var context = GetContext(new HandlerMethodDescriptor());
context.Result = expected;
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.Same(expected, context.Result);
}
[Fact]
public void OnPageHandlerExecuting_DoesNothing_IfHandlerIsNotSelected_WhenRequestsIsNotOptions()
{
// Arrange
var context = GetContext(handlerMethodDescriptor: null);
context.HttpContext.Request.Method = "PUT";
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.Null(context.Result);
}
[Fact]
public void OnPageHandlerExecuting_DoesNotOverwriteResult_IfHandlerIsNotSelected_WhenRequestsIsNotOptions()
{
// Arrange
var expected = new PageResult();
var context = GetContext(handlerMethodDescriptor: null);
context.HttpContext.Request.Method = "DELETE";
context.Result = expected;
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.Same(expected, context.Result);
}
[Fact]
public void OnPageHandlerExecuting_DoesNothing_ForOptionsRequestWhenHandlerIsSelected()
{
// Arrange
var context = GetContext(new HandlerMethodDescriptor());
context.HttpContext.Request.Method = "Options";
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.Null(context.Result);
}
[Fact]
public void OnPageHandlerExecuting_DoesNotOverwriteResult_ForOptionsRequestWhenNoHandler()
{
// Arrange
var expected = new NotFoundResult();
var context = GetContext(new HandlerMethodDescriptor());
context.Result = expected;
context.HttpContext.Request.Method = "Options";
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.Same(expected, context.Result);
}
[Fact]
public void OnPageHandlerExecuting_SetsResult_ForOptionsRequestWhenNoHandlerIsSelected()
{
// Arrange
var context = GetContext(handlerMethodDescriptor: null);
context.HttpContext.Request.Method = "Options";
var filter = new HandleOptionsRequestsPageFilter();
// Act
filter.OnPageHandlerExecuting(context);
// Assert
Assert.IsType<OkResult>(context.Result);
}
private static PageHandlerExecutingContext GetContext(HandlerMethodDescriptor handlerMethodDescriptor)
{
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new PageActionDescriptor());
var pageContext = new PageContext(actionContext);
return new PageHandlerExecutingContext(pageContext, Array.Empty<IFilterMetadata>(), handlerMethodDescriptor, new Dictionary<string, object>(), new object());
}
}
}

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.Extensions.Options;
using Xunit;
@ -30,7 +31,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Assert
Assert.Collection(
context.PageApplicationModel.Filters,
f => Assert.IsType<PageHandlerPageFilter>(f));
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f));
}
private class PageWithAuthorizeHandlers : Page
@ -63,6 +65,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Collection(
context.PageApplicationModel.Filters,
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f),
f => Assert.IsType<AuthorizeFilter>(f));
}
@ -102,6 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Collection(
context.PageApplicationModel.Filters,
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f),
f => authorizeFilter = Assert.IsType<AuthorizeFilter>(f));
// Basic + Basic2 + Derived authorize
@ -143,6 +147,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Collection(
context.PageApplicationModel.Filters,
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f),
f => Assert.IsType<AllowAnonymousFilter>(f));
}
@ -163,7 +168,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
var defaultProvider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }));
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }),
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
defaultProvider.OnProvidersExecuting(context);
return context;

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
@ -31,7 +32,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Assert
Assert.Collection(
context.PageApplicationModel.Filters,
f => Assert.IsType<PageHandlerPageFilter>(f));
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f));
}
private class PageWithoutResponseCache : Page
@ -66,6 +68,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
context.PageApplicationModel.Filters,
f => { },
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f),
f =>
{
var filter = Assert.IsType<ResponseCacheFilter>(f);
@ -112,6 +115,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
context.PageApplicationModel.Filters,
f => { },
f => Assert.IsType<PageHandlerPageFilter>(f),
f => Assert.IsType<HandleOptionsRequestsPageFilter>(f),
f =>
{
var filter = Assert.IsType<ResponseCacheFilter>(f);
@ -139,7 +143,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
var defaultProvider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions()));
Options.Create(new MvcOptions()),
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
defaultProvider.OnProvidersExecuting(context);
return context;

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -49,6 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
Assert.True(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses);
Assert.True(apiBehaviorOptions.SuppressMapClientErrors);
Assert.True(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
Assert.False(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
}
[Fact]
@ -80,6 +81,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
Assert.True(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses);
Assert.True(apiBehaviorOptions.SuppressMapClientErrors);
Assert.True(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
Assert.False(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
}
[Fact]
@ -111,6 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
Assert.False(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses);
Assert.False(apiBehaviorOptions.SuppressMapClientErrors);
Assert.False(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
}
[Fact]
@ -142,6 +145,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
Assert.False(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses);
Assert.False(apiBehaviorOptions.SuppressMapClientErrors);
Assert.False(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
}
// This just does the minimum needed to be able to resolve these options.

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>

View File

@ -0,0 +1,17 @@
@page
@functions {
public string Source { get; set; }
public void OnGet()
{
Source = "OnGet";
}
public void OnOptions(string message)
{
Source = "OnOptions";
}
}
Hello from @Source!