Add EndpointMetadata to ActionDescriptor and hookup CORS (#8158)

This commit is contained in:
James Newton-King 2018-07-28 16:12:54 +12:00 committed by GitHub
parent 556880872d
commit c01c7075be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 716 additions and 445 deletions

View File

@ -16,87 +16,87 @@
<BenchmarksOnlyMySqlConnectorPackageVersion>0.42.1</BenchmarksOnlyMySqlConnectorPackageVersion> <BenchmarksOnlyMySqlConnectorPackageVersion>0.42.1</BenchmarksOnlyMySqlConnectorPackageVersion>
<BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>2.1.0</BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion> <BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>2.1.0</BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>
<BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>2.1.0-rc1-final</BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion> <BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>2.1.0-rc1-final</BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>
<InternalAspNetCoreAnalyzersPackageVersion>2.2.0-preview1-34784</InternalAspNetCoreAnalyzersPackageVersion> <InternalAspNetCoreAnalyzersPackageVersion>2.2.0-preview1-34816</InternalAspNetCoreAnalyzersPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17099</InternalAspNetCoreSdkPackageVersion> <InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17099</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAllPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAllPackageVersion> <MicrosoftAspNetCoreAllPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAllPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAnalyzerTestingPackageVersion> <MicrosoftAspNetCoreAnalyzerTestingPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAntiforgeryPackageVersion> <MicrosoftAspNetCoreAntiforgeryPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion> <MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAuthenticationCorePackageVersion> <MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion> <MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAuthenticationPackageVersion> <MicrosoftAspNetCoreAuthenticationPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion> <MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion> <MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion> <MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreCookiePolicyPackageVersion> <MicrosoftAspNetCoreCookiePolicyPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreCorsPackageVersion> <MicrosoftAspNetCoreCorsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion> <MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreDiagnosticsPackageVersion> <MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreHostingAbstractionsPackageVersion> <MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreHostingPackageVersion> <MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion> <MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreHttpExtensionsPackageVersion> <MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreHttpPackageVersion> <MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreJsonPatchPackageVersion> <MicrosoftAspNetCoreJsonPatchPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreLocalizationPackageVersion> <MicrosoftAspNetCoreLocalizationPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreLocalizationRoutingPackageVersion> <MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion> <MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion> <MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRazorDesignPackageVersion> <MicrosoftAspNetCoreRazorDesignPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorLanguagePackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRazorLanguagePackageVersion> <MicrosoftAspNetCoreRazorLanguagePackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRazorLanguagePackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRazorRuntimePackageVersion> <MicrosoftAspNetCoreRazorRuntimePackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion> <MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion> <MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreResponseCachingPackageVersion> <MicrosoftAspNetCoreResponseCachingPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion> <MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreRoutingPackageVersion> <MicrosoftAspNetCoreRoutingPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreServerIISIntegrationPackageVersion> <MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreServerKestrelPackageVersion> <MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreSessionPackageVersion> <MicrosoftAspNetCoreSessionPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreStaticFilesPackageVersion> <MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreTestHostPackageVersion> <MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreTestingPackageVersion> <MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview1-34784</MicrosoftAspNetCoreWebUtilitiesPackageVersion> <MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview1-34816</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion> <MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion> <MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion> <MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview1-34784</MicrosoftCodeAnalysisRazorPackageVersion> <MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview1-34816</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion> <MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsCachingMemoryPackageVersion> <MicrosoftExtensionsCachingMemoryPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion> <MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsConfigurationCommandLinePackageVersion> <MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsConfigurationJsonPackageVersion> <MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsConfigurationPackageVersion> <MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion> <MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsDependencyInjectionPackageVersion> <MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.1.0</MicrosoftExtensionsDependencyModelPackageVersion> <MicrosoftExtensionsDependencyModelPackageVersion>2.1.0</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsDiagnosticAdapterPackageVersion> <MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion> <MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsFileProvidersCompositePackageVersion> <MicrosoftExtensionsFileProvidersCompositePackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion> <MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsFileSystemGlobbingPackageVersion> <MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion> <MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsLocalizationPackageVersion> <MicrosoftExtensionsLocalizationPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsLoggingAbstractionsPackageVersion> <MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsLoggingConsolePackageVersion> <MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsLoggingDebugPackageVersion> <MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsLoggingPackageVersion> <MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsLoggingTestingPackageVersion> <MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion> <MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsOptionsPackageVersion> <MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion> <MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsPrimitivesPackageVersion> <MicrosoftExtensionsPrimitivesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion> <MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsPropertyHelperSourcesPackageVersion> <MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsSecurityHelperSourcesPackageVersion> <MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion> <MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsValueStopwatchSourcesPackageVersion> <MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.2.0-preview1-34784</MicrosoftExtensionsWebEncodersPackageVersion> <MicrosoftExtensionsWebEncodersPackageVersion>2.2.0-preview1-34816</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion> <MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion> <MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview1-26618-02</MicrosoftNETCoreApp22PackageVersion> <MicrosoftNETCoreApp22PackageVersion>2.2.0-preview1-26618-02</MicrosoftNETCoreApp22PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview1-34784</MicrosoftNetHttpHeadersPackageVersion> <MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview1-34816</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>2.2.0-preview1-34784</MicrosoftNETSdkRazorPackageVersion> <MicrosoftNETSdkRazorPackageVersion>2.2.0-preview1-34816</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion> <MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion> <MoqPackageVersion>4.7.49</MoqPackageVersion>
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion> <NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>

View File

@ -36,6 +36,8 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
/// </summary> /// </summary>
public IList<IActionConstraintMetadata> ActionConstraints { get; set; } public IList<IActionConstraintMetadata> ActionConstraints { get; set; }
public IList<object> EndpointMetadata { get; set; }
/// <summary> /// <summary>
/// The set of parameters associated with this action. /// The set of parameters associated with this action.
/// </summary> /// </summary>

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
public SelectorModel() public SelectorModel()
{ {
ActionConstraints = new List<IActionConstraintMetadata>(); ActionConstraints = new List<IActionConstraintMetadata>();
EndpointMetadata = new List<object>();
} }
public SelectorModel(SelectorModel other) public SelectorModel(SelectorModel other)
@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
} }
ActionConstraints = new List<IActionConstraintMetadata>(other.ActionConstraints); ActionConstraints = new List<IActionConstraintMetadata>(other.ActionConstraints);
EndpointMetadata = new List<object>(other.EndpointMetadata);
if (other.AttributeRouteModel != null) if (other.AttributeRouteModel != null)
{ {
@ -32,5 +34,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
public AttributeRouteModel AttributeRouteModel { get; set; } public AttributeRouteModel AttributeRouteModel { get; set; }
public IList<IActionConstraintMetadata> ActionConstraints { get; } public IList<IActionConstraintMetadata> ActionConstraints { get; }
public IList<object> EndpointMetadata { get; }
} }
} }

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing.Metadata;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources; using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Internal namespace Microsoft.AspNetCore.Mvc.Internal
@ -163,6 +164,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
} }
AddActionConstraints(actionDescriptor, actionSelector, controllerConstraints); AddActionConstraints(actionDescriptor, actionSelector, controllerConstraints);
// REVIEW: Need to get metadata from controller
actionDescriptor.EndpointMetadata = actionSelector.EndpointMetadata.ToList();
} }
return actionDescriptors; return actionDescriptors;

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing.Metadata;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -641,6 +642,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
} }
AddRange(selectorModel.ActionConstraints, attributes.OfType<IActionConstraintMetadata>()); AddRange(selectorModel.ActionConstraints, attributes.OfType<IActionConstraintMetadata>());
AddRange(selectorModel.EndpointMetadata, attributes);
// Simple case, all HTTP method attributes apply // Simple case, all HTTP method attributes apply
var httpMethods = attributes var httpMethods = attributes
@ -652,6 +654,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
if (httpMethods.Length > 0) if (httpMethods.Length > 0)
{ {
selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(httpMethods)); selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(httpMethods));
selectorModel.EndpointMetadata.Add(new HttpMethodMetadata(httpMethods));
} }
return selectorModel; return selectorModel;

View File

@ -3,15 +3,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.EndpointConstraints; using Microsoft.AspNetCore.Routing.EndpointConstraints;
using Microsoft.AspNetCore.Routing.Matchers; using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.AspNetCore.Routing.Metadata;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Template;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@ -316,6 +319,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
metadata.Add(source); metadata.Add(source);
metadata.Add(action); metadata.Add(action);
if (action.EndpointMetadata != null)
{
metadata.AddRange(action.EndpointMetadata);
}
if (!string.IsNullOrEmpty(routeName)) if (!string.IsNullOrEmpty(routeName))
{ {
metadata.Add(new RouteNameMetadata(routeName)); metadata.Add(new RouteNameMetadata(routeName));
@ -334,11 +342,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
// Currently they need to implement IActionConstraintMetadata // Currently they need to implement IActionConstraintMetadata
foreach (var actionConstraint in action.ActionConstraints) foreach (var actionConstraint in action.ActionConstraints)
{ {
if (actionConstraint is HttpMethodActionConstraint httpMethodActionConstraint) if (actionConstraint is IEndpointConstraintMetadata)
{
metadata.Add(new HttpMethodEndpointConstraint(httpMethodActionConstraint.HttpMethods));
}
else if (actionConstraint is IEndpointConstraintMetadata)
{ {
// The constraint might have been added earlier, e.g. it is also a filter descriptor // The constraint might have been added earlier, e.g. it is also a filter descriptor
if (!metadata.Contains(actionConstraint)) if (!metadata.Contains(actionConstraint))

View File

@ -6,7 +6,7 @@ using System.Linq;
using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Routing.Metadata;
namespace Microsoft.AspNetCore.Mvc.Cors.Internal namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{ {
@ -67,17 +67,18 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
if (isCorsEnabledGlobally || corsOnController || corsOnAction) if (isCorsEnabledGlobally || corsOnController || corsOnAction)
{ {
UpdateHttpMethodActionConstraint(actionModel); UpdateActionToAcceptCorsPreflight(actionModel);
} }
} }
} }
} }
private static void UpdateHttpMethodActionConstraint(ActionModel actionModel) private static void UpdateActionToAcceptCorsPreflight(ActionModel actionModel)
{ {
for (var i = 0; i < actionModel.Selectors.Count; i++) for (var i = 0; i < actionModel.Selectors.Count; i++)
{ {
var selectorModel = actionModel.Selectors[i]; var selectorModel = actionModel.Selectors[i];
for (var j = 0; j < selectorModel.ActionConstraints.Count; j++) for (var j = 0; j < selectorModel.ActionConstraints.Count; j++)
{ {
if (selectorModel.ActionConstraints[j] is HttpMethodActionConstraint httpConstraint) if (selectorModel.ActionConstraints[j] is HttpMethodActionConstraint httpConstraint)
@ -85,6 +86,14 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
selectorModel.ActionConstraints[j] = new CorsHttpMethodActionConstraint(httpConstraint); selectorModel.ActionConstraints[j] = new CorsHttpMethodActionConstraint(httpConstraint);
} }
} }
for (int j = 0; j < selectorModel.EndpointMetadata.Count; j++)
{
if (selectorModel.EndpointMetadata[j] is HttpMethodMetadata httpMethodMetadata)
{
selectorModel.EndpointMetadata[j] = new HttpMethodMetadata(httpMethodMetadata.HttpMethods, true);
}
}
} }
} }
} }

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing.Metadata;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq; using Moq;
using Xunit; using Xunit;
@ -251,6 +252,62 @@ namespace Microsoft.AspNetCore.Mvc.Internal
Assert.Equal(nameof(ConventionallyRoutedController.ConventionalAction), actionConstraint.Value); Assert.Equal(nameof(ConventionallyRoutedController.ConventionalAction), actionConstraint.Value);
} }
[Fact]
public void GetDescriptors_ActionWithHttpMethods_AddedToEndpointMetadata()
{
// Arrange & Act
var descriptors = GetDescriptors(
typeof(AttributeRoutedController).GetTypeInfo());
// Assert
var action = Assert.Single(descriptors);
Assert.NotNull(action.EndpointMetadata);
Assert.Collection(action.EndpointMetadata,
metadata => Assert.IsType<HttpGetAttribute>(metadata),
metadata =>
{
var httpMethodMetadata = Assert.IsType<HttpMethodMetadata>(metadata);
Assert.False(httpMethodMetadata.AcceptCorsPreflight);
Assert.Equal("GET", Assert.Single(httpMethodMetadata.HttpMethods));
});
}
[Fact]
public void GetDescriptors_ActionWithMultipleHttpMethods_SingleHttpMethodMetadata()
{
// Arrange & Act
var descriptors = GetDescriptors(
typeof(NonDuplicatedAttributeRouteController).GetTypeInfo());
// Assert
var actions = descriptors
.OfType<ControllerActionDescriptor>()
.Where(d => d.ActionName == nameof(NonDuplicatedAttributeRouteController.DifferentHttpMethods));
Assert.Collection(actions,
InspectElement("GET"),
InspectElement("POST"),
InspectElement("PUT"),
InspectElement("PATCH"),
InspectElement("DELETE"));
Action<ControllerActionDescriptor> InspectElement(string httpMethod)
{
return (descriptor) =>
{
var httpMethodAttribute = Assert.Single(descriptor.EndpointMetadata.OfType<HttpMethodAttribute>());
Assert.Equal(httpMethod, httpMethodAttribute.HttpMethods.Single(), ignoreCase: true);
var httpMethodMetadata = Assert.Single(descriptor.EndpointMetadata.OfType<IHttpMethodMetadata>());
Assert.Equal(httpMethod, httpMethodMetadata.HttpMethods.Single(), ignoreCase: true);
Assert.False(httpMethodMetadata.AcceptCorsPreflight);
};
}
}
[Fact] [Fact]
public void GetDescriptors_AddsControllerAndActionDefaults_ToAttributeRoutedActions() public void GetDescriptors_AddsControllerAndActionDefaults_ToAttributeRoutedActions()
{ {

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Routing.Metadata;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq; using Moq;
@ -36,6 +38,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
@ -55,10 +59,12 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
public void CreateControllerModel_CustomCorsFilter_ReplacesHttpConstraints() public void CreateControllerModel_CustomCorsFilter_EnablesCorsPreflight()
{ {
// Arrange // Arrange
var corsProvider = new CorsApplicationModelProvider(); var corsProvider = new CorsApplicationModelProvider();
@ -73,6 +79,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
@ -92,6 +100,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
@ -111,10 +121,12 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
public void BuildActionModel_CustomCorsAuthorizationFilterOnAction_ReplacesHttpConstraints() public void BuildActionModel_CustomCorsAuthorizationFilterOnAction_EnablesCorsPreflight()
{ {
// Arrange // Arrange
var corsProvider = new CorsApplicationModelProvider(); var corsProvider = new CorsApplicationModelProvider();
@ -129,10 +141,12 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
public void CreateControllerModel_EnableCorsGloballyReplacesHttpMethodConstraints() public void CreateControllerModel_EnableCorsGloballyEnablesCorsPreflight()
{ {
// Arrange // Arrange
var corsProvider = new CorsApplicationModelProvider(); var corsProvider = new CorsApplicationModelProvider();
@ -150,10 +164,12 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
public void CreateControllerModel_DisableCorsGloballyReplacesHttpMethodConstraints() public void CreateControllerModel_DisableCorsGloballyEnablesCorsPreflight()
{ {
// Arrange // Arrange
var corsProvider = new CorsApplicationModelProvider(); var corsProvider = new CorsApplicationModelProvider();
@ -169,10 +185,12 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
public void CreateControllerModel_CustomCorsFilterGloballyReplacesHttpMethodConstraints() public void CreateControllerModel_CustomCorsFilterGloballyEnablesCorsPreflight()
{ {
// Arrange // Arrange
var corsProvider = new CorsApplicationModelProvider(); var corsProvider = new CorsApplicationModelProvider();
@ -188,6 +206,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsType<CorsHttpMethodActionConstraint>(constraint); Assert.IsType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.True(httpMethodMetadata.AcceptCorsPreflight);
} }
[Fact] [Fact]
@ -206,6 +226,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
var selector = Assert.Single(action.Selectors); var selector = Assert.Single(action.Selectors);
var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint); var constraint = Assert.Single(selector.ActionConstraints, c => c is HttpMethodActionConstraint);
Assert.IsNotType<CorsHttpMethodActionConstraint>(constraint); Assert.IsNotType<CorsHttpMethodActionConstraint>(constraint);
var httpMethodMetadata = Assert.Single(selector.EndpointMetadata.OfType<HttpMethodMetadata>());
Assert.False(httpMethodMetadata.AcceptCorsPreflight);
} }
private static ApplicationModelProviderContext GetProviderContext(Type controllerType) private static ApplicationModelProviderContext GetProviderContext(Type controllerType)

View File

@ -0,0 +1,34 @@
// 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.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
public class CorsGlobalRoutingTests : CorsTestsBase<CorsWebSite.StartupWithGlobalRouting>
{
public CorsGlobalRoutingTests(MvcTestFixture<CorsWebSite.StartupWithGlobalRouting> fixture)
: base(fixture)
{
}
[Fact] // This intentionally returns a 405 with global routing
public override async Task PreflightRequestOnNonCorsEnabledController_DoesNotMatchTheAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/Post");
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "POST");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
}
}
}

View File

@ -1,354 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{ {
public class CorsTests : IClassFixture<MvcTestFixture<CorsWebSite.Startup>> public class CorsTests : CorsTestsBase<CorsWebSite.Startup>
{ {
public CorsTests(MvcTestFixture<CorsWebSite.Startup> fixture) public CorsTests(MvcTestFixture<CorsWebSite.Startup> fixture)
: base(fixture)
{ {
Client = fixture.CreateDefaultClient();
}
public HttpClient Client { get; }
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
public async Task ResourceWithSimpleRequestPolicy_Allows_SimpleRequests(string method)
{
// Arrange
var origin = "http://example.com";
var request = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Cors/GetBlogComments");
request.Headers.Add(CorsConstants.Origin, origin);
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"comment1\",\"comment2\",\"comment3\"]", content);
var responseHeaders = response.Headers;
var header = Assert.Single(response.Headers);
Assert.Equal(CorsConstants.AccessControlAllowOrigin, header.Key);
Assert.Equal(new[] { "*" }, header.Value.ToArray());
}
[Fact]
public async Task OptionsRequest_NonPreflight_ExecutesOptionsAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/GetOptions");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"Create\",\"Update\",\"Delete\"]", content);
Assert.Empty(response.Headers);
}
[Fact]
public async Task PreflightRequestOnNonCorsEnabledController_ExecutesOptionsAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/GetOptions");
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "POST");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"Create\",\"Update\",\"Delete\"]", content);
Assert.Empty(response.Headers);
}
[Fact]
public async Task PreflightRequestOnNonCorsEnabledController_DoesNotMatchTheAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/Post");
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "POST");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
[InlineData("PUT")]
public async Task PolicyFailed_Disallows_PreFlightRequest(string method)
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/Cors/GetBlogComments");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, method);
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
// MVC applied the policy and since that did not pass, there were no access control headers.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// It should short circuit and hence no result.
var content = await response.Content.ReadAsStringAsync();
Assert.Equal(string.Empty, content);
}
[Fact]
public async Task SuccessfulCorsRequest_AllowsCredentials_IfThePolicyAllowsCredentials()
{
// Arrange
var request = new HttpRequestMessage(
HttpMethod.Put,
"http://localhost/Cors/EditUserComment?userComment=abcd");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlExposeHeaders, "exposed1,exposed2");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseHeaders = response.Headers;
Assert.Equal(
new[] { "http://example.com" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowOrigin).ToArray());
Assert.Equal(
new[] { "true" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowCredentials).ToArray());
Assert.Equal(
new[] { "exposed1,exposed2" },
responseHeaders.GetValues(CorsConstants.AccessControlExposeHeaders).ToArray());
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("abcd", content);
}
[Fact]
public async Task SuccessfulPreflightRequest_AllowsCredentials_IfThePolicyAllowsCredentials()
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/Cors/EditUserComment?userComment=abcd");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "PUT");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "header1,header2");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseHeaders = response.Headers;
Assert.Equal(
new[] { "http://example.com" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowOrigin).ToArray());
Assert.Equal(
new[] { "true" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowCredentials).ToArray());
Assert.Equal(
new[] { "header1,header2" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowHeaders).ToArray());
Assert.Equal(
new[] { "PUT" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowMethods).ToArray());
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Fact]
public async Task PolicyFailed_Allows_ActualRequest_WithMissingResponseHeaders()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Put, "http://localhost/Cors/GetUserComments");
// Adding a custom header makes it a non simple request.
request.Headers.Add(CorsConstants.Origin, "http://example2.com");
// Act
var response = await Client.SendAsync(request);
// Assert
// MVC applied the policy and since that did not pass, there were no access control headers.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// It still have executed the action.
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"usercomment1\",\"usercomment2\",\"usercomment3\"]", content);
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
public async Task DisableCors_ActionsCanOverride_ControllerLevel(string method)
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Cors/GetExclusiveContent");
// Exclusive content is not available on other sites.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
// Since there are no response headers, the client should step in to block the content.
Assert.Empty(response.Headers);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("exclusive", content);
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
public async Task DisableCors_PreFlight_ActionsCanOverride_ControllerLevel(string method)
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/Cors/GetExclusiveContent");
// Exclusive content is not available on other sites.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, method);
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
// Since there are no response headers, the client should step in to block the content.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// Nothing gets executed for a pre-flight request.
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Theory]
[InlineData("http://localhost/api/store/actionusingcontrollercorssettings")]
[InlineData("http://localhost/api/store/actionwithcorssettings")]
public async Task CorsFilter_RunsBeforeOtherAuthorizationFilters(string url)
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod(CorsConstants.PreflightHttpMethod), url);
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "GET");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseHeaders = response.Headers;
Assert.Equal(
new[] { "http://example.com" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowOrigin).ToArray());
Assert.Equal(
new[] { "true" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowCredentials).ToArray());
Assert.Equal(
new[] { "Custom" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowHeaders).ToArray());
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Fact]
public async Task DisableCorsFilter_RunsBeforeOtherAuthorizationFilters()
{
// Controller has an authorization filter and Cors filter and the action has a DisableCors filter
// In this scenario, the CorsFilter should be executed before any other authorization filters
// i.e irrespective of where the Cors filter is applied(controller or action), Cors filters must
// always be executed before any other type of authorization filters.
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/api/store/actionwithcorsdisabled");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "GET");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// Nothing gets executed for a pre-flight request.
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Fact]
public async Task CorsFilter_OnAction_PreferredOverController_AndAuthorizationFiltersRunAfterCors()
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/api/store/actionwithdifferentcorspolicy");
request.Headers.Add(CorsConstants.Origin, "http://notexpecteddomain.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "GET");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// Nothing gets executed for a pre-flight request.
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
} }
} }
} }

View File

@ -0,0 +1,359 @@
// 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.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
public abstract class CorsTestsBase<TStartup> : IClassFixture<MvcTestFixture<TStartup>> where TStartup : class
{
protected CorsTestsBase(MvcTestFixture<TStartup> fixture)
{
var factory = fixture.Factories.FirstOrDefault() ?? fixture.WithWebHostBuilder(ConfigureWebHostBuilder);
Client = factory.CreateDefaultClient();
}
private static void ConfigureWebHostBuilder(IWebHostBuilder builder) =>
builder.UseStartup<TStartup>();
public HttpClient Client { get; }
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
public async Task ResourceWithSimpleRequestPolicy_Allows_SimpleRequests(string method)
{
// Arrange
var origin = "http://example.com";
var request = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Cors/GetBlogComments");
request.Headers.Add(CorsConstants.Origin, origin);
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"comment1\",\"comment2\",\"comment3\"]", content);
var responseHeaders = response.Headers;
var header = Assert.Single(response.Headers);
Assert.Equal(CorsConstants.AccessControlAllowOrigin, header.Key);
Assert.Equal(new[] { "*" }, header.Value.ToArray());
}
[Fact]
public async Task OptionsRequest_NonPreflight_ExecutesOptionsAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/GetOptions");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"Create\",\"Update\",\"Delete\"]", content);
Assert.Empty(response.Headers);
}
[Fact]
public async Task PreflightRequestOnNonCorsEnabledController_ExecutesOptionsAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/GetOptions");
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "POST");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"Create\",\"Update\",\"Delete\"]", content);
Assert.Empty(response.Headers);
}
[Fact]
public virtual async Task PreflightRequestOnNonCorsEnabledController_DoesNotMatchTheAction()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("OPTIONS"), "http://localhost/NonCors/Post");
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "POST");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
[InlineData("PUT")]
public async Task PolicyFailed_Disallows_PreFlightRequest(string method)
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/Cors/GetBlogComments");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, method);
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
// MVC applied the policy and since that did not pass, there were no access control headers.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// It should short circuit and hence no result.
var content = await response.Content.ReadAsStringAsync();
Assert.Equal(string.Empty, content);
}
[Fact]
public async Task SuccessfulCorsRequest_AllowsCredentials_IfThePolicyAllowsCredentials()
{
// Arrange
var request = new HttpRequestMessage(
HttpMethod.Put,
"http://localhost/Cors/EditUserComment?userComment=abcd");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlExposeHeaders, "exposed1,exposed2");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseHeaders = response.Headers;
Assert.Equal(
new[] { "http://example.com" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowOrigin).ToArray());
Assert.Equal(
new[] { "true" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowCredentials).ToArray());
Assert.Equal(
new[] { "exposed1,exposed2" },
responseHeaders.GetValues(CorsConstants.AccessControlExposeHeaders).ToArray());
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("abcd", content);
}
[Fact]
public async Task SuccessfulPreflightRequest_AllowsCredentials_IfThePolicyAllowsCredentials()
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/Cors/EditUserComment?userComment=abcd");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "PUT");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "header1,header2");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseHeaders = response.Headers;
Assert.Equal(
new[] { "http://example.com" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowOrigin).ToArray());
Assert.Equal(
new[] { "true" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowCredentials).ToArray());
Assert.Equal(
new[] { "header1,header2" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowHeaders).ToArray());
Assert.Equal(
new[] { "PUT" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowMethods).ToArray());
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Fact]
public async Task PolicyFailed_Allows_ActualRequest_WithMissingResponseHeaders()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Put, "http://localhost/Cors/GetUserComments");
// Adding a custom header makes it a non simple request.
request.Headers.Add(CorsConstants.Origin, "http://example2.com");
// Act
var response = await Client.SendAsync(request);
// Assert
// MVC applied the policy and since that did not pass, there were no access control headers.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// It still have executed the action.
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("[\"usercomment1\",\"usercomment2\",\"usercomment3\"]", content);
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
public async Task DisableCors_ActionsCanOverride_ControllerLevel(string method)
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Cors/GetExclusiveContent");
// Exclusive content is not available on other sites.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
// Since there are no response headers, the client should step in to block the content.
Assert.Empty(response.Headers);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("exclusive", content);
}
[Theory]
[InlineData("GET")]
[InlineData("HEAD")]
[InlineData("POST")]
public async Task DisableCors_PreFlight_ActionsCanOverride_ControllerLevel(string method)
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/Cors/GetExclusiveContent");
// Exclusive content is not available on other sites.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, method);
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
// Since there are no response headers, the client should step in to block the content.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// Nothing gets executed for a pre-flight request.
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Theory]
[InlineData("http://localhost/api/store/actionusingcontrollercorssettings")]
[InlineData("http://localhost/api/store/actionwithcorssettings")]
public async Task CorsFilter_RunsBeforeOtherAuthorizationFilters(string url)
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod(CorsConstants.PreflightHttpMethod), url);
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "GET");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseHeaders = response.Headers;
Assert.Equal(
new[] { "http://example.com" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowOrigin).ToArray());
Assert.Equal(
new[] { "true" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowCredentials).ToArray());
Assert.Equal(
new[] { "Custom" },
responseHeaders.GetValues(CorsConstants.AccessControlAllowHeaders).ToArray());
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Fact]
public async Task DisableCorsFilter_RunsBeforeOtherAuthorizationFilters()
{
// Controller has an authorization filter and Cors filter and the action has a DisableCors filter
// In this scenario, the CorsFilter should be executed before any other authorization filters
// i.e irrespective of where the Cors filter is applied(controller or action), Cors filters must
// always be executed before any other type of authorization filters.
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/api/store/actionwithcorsdisabled");
// Adding a custom header makes it a non-simple request.
request.Headers.Add(CorsConstants.Origin, "http://example.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "GET");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// Nothing gets executed for a pre-flight request.
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
[Fact]
public async Task CorsFilter_OnAction_PreferredOverController_AndAuthorizationFiltersRunAfterCors()
{
// Arrange
var request = new HttpRequestMessage(
new HttpMethod(CorsConstants.PreflightHttpMethod),
"http://localhost/api/store/actionwithdifferentcorspolicy");
request.Headers.Add(CorsConstants.Origin, "http://notexpecteddomain.com");
request.Headers.Add(CorsConstants.AccessControlRequestMethod, "GET");
request.Headers.Add(CorsConstants.AccessControlRequestHeaders, "Custom");
// Act
var response = await Client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Empty(response.Headers);
// Nothing gets executed for a pre-flight request.
var content = await response.Content.ReadAsStringAsync();
Assert.Empty(content);
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Net; using System.Net;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Xunit; using Xunit;
@ -29,5 +30,27 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.True(result); Assert.True(result);
} }
// This behaves differently right now because the action/endpoint constraints are always
// executed after the DFA nodes like (HttpMethodMatcherPolicy). You don't have the flexibility
// to do what this test is doing in old-style routing.
[Fact]
public override async Task VersionedApi_CanUseConstraintOrder_ToChangeSelectedAction()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Delete, "http://localhost/" + "Customers/5?version=2");
// Act
var response = await Client.SendAsync(message);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<RoutingResult>(body);
Assert.Equal("Customers", result.Controller);
Assert.Equal("AnyV2OrHigherWithId", result.Action);
}
} }
} }

View File

@ -508,7 +508,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
} }
[Fact] [Fact]
public async Task VersionedApi_CanUseConstraintOrder_ToChangeSelectedAction() public virtual async Task VersionedApi_CanUseConstraintOrder_ToChangeSelectedAction()
{ {
// Arrange // Arrange
var message = new HttpRequestMessage(HttpMethod.Delete, "http://localhost/" + "Customers/5?version=2"); var message = new HttpRequestMessage(HttpMethod.Delete, "http://localhost/" + "Customers/5?version=2");
@ -551,7 +551,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal(path, actualUrl); Assert.Equal(path, actualUrl);
} }
private class RoutingResult protected class RoutingResult
{ {
public string[] ExpectedUrls { get; set; } public string[] ExpectedUrls { get; set; }

View File

@ -0,0 +1,26 @@
// 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.IO;
using Microsoft.AspNetCore.Hosting;
namespace CorsWebSite
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseKestrel()
.UseIISIntegration();
}
}

View File

@ -76,20 +76,5 @@ namespace CorsWebSite
{ {
app.UseMvc(); app.UseMvc();
} }
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseKestrel()
.UseIISIntegration();
} }
} }

View File

@ -0,0 +1,80 @@
// 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.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace CorsWebSite
{
public class StartupWithGlobalRouting
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableGlobalRouting = true);
services.Configure<CorsOptions>(options =>
{
options.AddPolicy(
"AllowAnySimpleRequest",
builder =>
{
builder.AllowAnyOrigin()
.WithMethods("GET", "POST", "HEAD");
});
options.AddPolicy(
"AllowSpecificOrigin",
builder =>
{
builder.WithOrigins("http://example.com");
});
options.AddPolicy(
"WithCredentials",
builder =>
{
builder.AllowCredentials()
.WithOrigins("http://example.com");
});
options.AddPolicy(
"WithCredentialsAnyOrigin",
builder =>
{
builder.AllowCredentials()
.AllowAnyOrigin()
.AllowAnyHeader()
.WithMethods("PUT", "POST")
.WithExposedHeaders("exposed1", "exposed2");
});
options.AddPolicy(
"AllowAll",
builder =>
{
builder.AllowCredentials()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin();
});
options.AddPolicy(
"Allow example.com",
builder =>
{
builder.AllowCredentials()
.AllowAnyMethod()
.AllowAnyHeader()
.WithOrigins("http://example.com");
});
});
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
}