Add MvcEndpointDataSource and functional tests (#7886)

This commit is contained in:
James Newton-King 2018-06-14 11:03:45 +12:00 committed by GitHub
parent 287a3c5e69
commit a7406d4497
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2535 additions and 74 deletions

15
Mvc.sln
View File

@ -172,6 +172,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPagesClassLibrary", "t
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Views.TestCommon", "test\Microsoft.AspNetCore.Mvc.Views.TestCommon\Microsoft.AspNetCore.Mvc.Views.TestCommon.csproj", "{51E3E785-A9D1-4196-BAFE-A17FF4304B89}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispatchingWebSite", "test\WebSites\DispatchingWebSite\DispatchingWebSite.csproj", "{ABB3737F-E518-4E40-8A9C-F3281D610E8F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -906,6 +908,18 @@ Global
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|x86.ActiveCfg = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|x86.Build.0 = Release|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Debug|x86.ActiveCfg = Debug|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Debug|x86.Build.0 = Debug|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Release|Any CPU.Build.0 = Release|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Release|x86.ActiveCfg = Release|Any CPU
{ABB3737F-E518-4E40-8A9C-F3281D610E8F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -976,6 +990,7 @@ Global
{E83D3745-9BCF-40E8-8D34-AFBA604C2439} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{17122147-ADFD-41C8-87D9-CCC582CCA8F9} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{51E3E785-A9D1-4196-BAFE-A17FF4304B89} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{ABB3737F-E518-4E40-8A9C-F3281D610E8F} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A}

View File

@ -5,91 +5,91 @@
<PropertyGroup Label="Package Versions">
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
<InternalAspNetCoreAnalyzersPackageVersion>2.2.0-preview1-34425</InternalAspNetCoreAnalyzersPackageVersion>
<InternalAspNetCoreAnalyzersPackageVersion>2.2.0-preview1-34462</InternalAspNetCoreAnalyzersPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17082</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorLanguagePackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRazorLanguagePackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview1-34425</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorLanguagePackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRazorLanguagePackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview1-34462</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview1-34425</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview1-34462</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.2.0-preview1-26606-01</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.2.0-preview1-34425</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.2.0-preview1-26612-04</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.2.0-preview1-34462</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview1-26606-01</MicrosoftNETCoreApp22PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview1-34425</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>2.2.0-preview1-34425</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview1-26612-04</MicrosoftNETCoreApp22PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview1-34462</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>2.2.0-preview1-34462</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
<NewtonsoftJsonBsonPackageVersion>1.0.1</NewtonsoftJsonBsonPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>4.6.0-preview1-26605-01</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.6.0-preview1-26605-01</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.6.0-preview1-26605-01</SystemThreadingTasksExtensionsPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>4.6.0-preview1-26611-02</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.6.0-preview1-26611-02</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.6.0-preview1-26611-02</SystemThreadingTasksExtensionsPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>

View File

@ -260,6 +260,13 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<MvcRouteHandler>(); // Only one per app
services.TryAddTransient<MvcAttributeRouteHandler>(); // Many per app
//
// Dispatching
//
services.TryAddEnumerable(
ServiceDescriptor.Singleton<EndpointDataSource, MvcEndpointDataSource>());
services.TryAddSingleton<MvcEndpointInvokerFactory>();
//
// Middleware pipeline filter related
//

View File

@ -0,0 +1,139 @@
// 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 System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Mvc.Internal
{
internal class MvcEndpointDataSource : EndpointDataSource
{
private readonly IActionDescriptorCollectionProvider _actions;
private readonly MvcEndpointInvokerFactory _invokerFactory;
private readonly IActionDescriptorChangeProvider[] _actionDescriptorChangeProviders;
private readonly List<Endpoint> _endpoints;
private IChangeToken _changeToken;
public MvcEndpointDataSource(
IActionDescriptorCollectionProvider actions,
MvcEndpointInvokerFactory invokerFactory,
IEnumerable<IActionDescriptorChangeProvider> actionDescriptorChangeProviders)
{
if (actions == null)
{
throw new ArgumentNullException(nameof(actions));
}
if (invokerFactory == null)
{
throw new ArgumentNullException(nameof(invokerFactory));
}
if (actionDescriptorChangeProviders == null)
{
throw new ArgumentNullException(nameof(actionDescriptorChangeProviders));
}
_actions = actions;
_invokerFactory = invokerFactory;
_actionDescriptorChangeProviders = actionDescriptorChangeProviders.ToArray();
_endpoints = new List<Endpoint>();
InitializeEndpoints();
}
private void InitializeEndpoints()
{
// note: this code has haxxx. This will only work in some constrained scenarios
foreach (var action in _actions.ActionDescriptors.Items)
{
if (action.AttributeRouteInfo == null)
{
// Action does not have an attribute route
continue;
}
RequestDelegate invokerDelegate = (context) =>
{
var values = context.Features.Get<IEndpointFeature>().Values;
var routeData = new RouteData();
foreach (var kvp in values)
{
routeData.Values.Add(kvp.Key, kvp.Value);
}
var actionContext = new ActionContext(context, routeData, action);
var invoker = _invokerFactory.CreateInvoker(actionContext);
return invoker.InvokeAsync();
};
var metadata = new List<object>();
// Add filter descriptors to endpoint metadata
metadata.AddRange(action.FilterDescriptors.OrderBy(f => f, FilterDescriptorOrderComparer.Comparer).Select(f => f.Filter));
if (action.ActionConstraints != null && action.ActionConstraints.Count > 0)
{
foreach (var actionConstraint in action.ActionConstraints)
{
if (actionConstraint is HttpMethodActionConstraint httpMethodActionConstraint)
{
metadata.Add(new HttpMethodEndpointConstraint(httpMethodActionConstraint.HttpMethods));
}
}
}
var metadataCollection = new EndpointMetadataCollection(metadata);
_endpoints.Add(new MatcherEndpoint(
next => invokerDelegate,
action.AttributeRouteInfo.Template,
action.RouteValues,
action.AttributeRouteInfo.Order,
metadataCollection,
action.DisplayName));
}
}
private IChangeToken GetCompositeChangeToken()
{
if (_actionDescriptorChangeProviders.Length == 1)
{
return _actionDescriptorChangeProviders[0].GetChangeToken();
}
var changeTokens = new IChangeToken[_actionDescriptorChangeProviders.Length];
for (var i = 0; i < _actionDescriptorChangeProviders.Length; i++)
{
changeTokens[i] = _actionDescriptorChangeProviders[i].GetChangeToken();
}
return new CompositeChangeToken(changeTokens);
}
public override IChangeToken ChangeToken
{
get
{
if (_changeToken == null)
{
_changeToken = GetCompositeChangeToken();
}
return _changeToken;
}
}
public override IReadOnlyList<Endpoint> Endpoints => _endpoints;
}
}

View File

@ -0,0 +1,41 @@
// 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 Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
namespace Microsoft.AspNetCore.Mvc.Internal
{
internal sealed class MvcEndpointInvokerFactory : IActionInvokerFactory
{
private readonly IActionInvokerFactory _invokerFactory;
private readonly IActionContextAccessor _actionContextAccessor;
public MvcEndpointInvokerFactory(
IActionInvokerFactory invokerFactory)
: this(invokerFactory, actionContextAccessor: null)
{
}
public MvcEndpointInvokerFactory(
IActionInvokerFactory invokerFactory,
IActionContextAccessor actionContextAccessor)
{
_invokerFactory = invokerFactory;
// The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext
// if possible.
_actionContextAccessor = actionContextAccessor;
}
public IActionInvoker CreateInvoker(ActionContext actionContext)
{
if (_actionContextAccessor != null)
{
_actionContextAccessor.ActionContext = actionContext;
}
return _invokerFactory.CreateInvoker(actionContext);
}
}
}

View File

@ -306,6 +306,13 @@ namespace Microsoft.AspNetCore.Mvc
typeof(ApiBehaviorApplicationModelProvider),
}
},
{
typeof(EndpointDataSource),
new Type[]
{
typeof(MvcEndpointDataSource),
}
},
};
}
}

View File

@ -0,0 +1,170 @@
// 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 System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.Extensions.Primitives;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Core.Test.Internal
{
public class MvcEndpointDataSourceTests
{
[Fact]
public void Endpoints_AccessParameters_InitializedFromProvider()
{
// Arrange
var routeValue = "Value";
var routeValues = new Dictionary<string, string>
{
["Name"] = routeValue
};
var displayName = "DisplayName!";
var order = 1;
var template = "/Template!";
var filterDescriptor = new FilterDescriptor(new ControllerActionFilter(), 1);
var mockDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
mockDescriptorProvider.Setup(m => m.ActionDescriptors).Returns(new ActionDescriptorCollection(new List<ActionDescriptor>
{
new ActionDescriptor
{
RouteValues = routeValues,
DisplayName = displayName,
AttributeRouteInfo = new AttributeRouteInfo
{
Order = order,
Template = template
},
FilterDescriptors = new List<FilterDescriptor>
{
filterDescriptor
}
}
}, 0));
// Act
var dataSource = new MvcEndpointDataSource(
mockDescriptorProvider.Object,
new MvcEndpointInvokerFactory(new ActionInvokerFactory(Array.Empty<IActionInvokerProvider>())),
Array.Empty<IActionDescriptorChangeProvider>());
// Assert
var endpoint = Assert.Single(dataSource.Endpoints);
var matcherEndpoint = Assert.IsType<MatcherEndpoint>(endpoint);
object endpointValue = matcherEndpoint.Values["Name"];
Assert.Equal(routeValue, endpointValue);
Assert.Equal(displayName, matcherEndpoint.DisplayName);
Assert.Equal(order, matcherEndpoint.Order);
Assert.Equal(template, matcherEndpoint.Template);
}
[Fact]
public void Endpoints_InvokeReturnedEndpoint_ActionInvokerProviderCalled()
{
// Arrange
var featureCollection = new FeatureCollection();
featureCollection.Set<IEndpointFeature>(new EndpointFeature
{
Values = new RouteValueDictionary()
});
var httpContextMock = new Mock<HttpContext>();
httpContextMock.Setup(m => m.Features).Returns(featureCollection);
var mockDescriptorProviderMock = new Mock<IActionDescriptorCollectionProvider>();
mockDescriptorProviderMock.Setup(m => m.ActionDescriptors).Returns(new ActionDescriptorCollection(new List<ActionDescriptor>
{
new ActionDescriptor
{
AttributeRouteInfo = new AttributeRouteInfo
{
Template = string.Empty
},
FilterDescriptors = new List<FilterDescriptor>()
}
}, 0));
var actionInvokerCalled = false;
var actionInvokerMock = new Mock<IActionInvoker>();
actionInvokerMock.Setup(m => m.InvokeAsync()).Returns(() =>
{
actionInvokerCalled = true;
return Task.CompletedTask;
});
var actionInvokerProviderMock = new Mock<IActionInvokerFactory>();
actionInvokerProviderMock.Setup(m => m.CreateInvoker(It.IsAny<ActionContext>())).Returns(actionInvokerMock.Object);
// Act
var dataSource = new MvcEndpointDataSource(
mockDescriptorProviderMock.Object,
new MvcEndpointInvokerFactory(actionInvokerProviderMock.Object),
Array.Empty<IActionDescriptorChangeProvider>());
// Assert
var endpoint = Assert.Single(dataSource.Endpoints);
var matcherEndpoint = Assert.IsType<MatcherEndpoint>(endpoint);
var invokerDelegate = matcherEndpoint.Invoker((next) => Task.CompletedTask);
invokerDelegate(httpContextMock.Object);
Assert.True(actionInvokerCalled);
}
[Fact]
public void ChangeToken_MultipleChangeTokenProviders_ComposedResult()
{
// Arrange
var featureCollection = new FeatureCollection();
featureCollection.Set<IEndpointFeature>(new EndpointFeature
{
Values = new RouteValueDictionary()
});
var httpContextMock = new Mock<HttpContext>();
httpContextMock.Setup(m => m.Features).Returns(featureCollection);
var mockDescriptorProviderMock = new Mock<IActionDescriptorCollectionProvider>();
mockDescriptorProviderMock.Setup(m => m.ActionDescriptors).Returns(new ActionDescriptorCollection(new List<ActionDescriptor>(), 0));
var actionInvokerMock = new Mock<IActionInvoker>();
var actionInvokerProviderMock = new Mock<IActionInvokerFactory>();
actionInvokerProviderMock.Setup(m => m.CreateInvoker(It.IsAny<ActionContext>())).Returns(actionInvokerMock.Object);
var changeTokenMock = new Mock<IChangeToken>();
var changeProvider1Mock = new Mock<IActionDescriptorChangeProvider>();
changeProvider1Mock.Setup(m => m.GetChangeToken()).Returns(changeTokenMock.Object);
var changeProvider2Mock = new Mock<IActionDescriptorChangeProvider>();
changeProvider2Mock.Setup(m => m.GetChangeToken()).Returns(changeTokenMock.Object);
var dataSource = new MvcEndpointDataSource(
mockDescriptorProviderMock.Object,
new MvcEndpointInvokerFactory(actionInvokerProviderMock.Object),
new[] { changeProvider1Mock.Object, changeProvider2Mock.Object });
// Act
var changeToken = dataSource.ChangeToken;
// Assert
var compositeChangeToken = Assert.IsType<CompositeChangeToken>(changeToken);
Assert.Equal(2, compositeChangeToken.ChangeTokens.Count);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@
<ProjectReference Include="..\WebSites\BasicWebSite\BasicWebSite.csproj" />
<ProjectReference Include="..\WebSites\ControllersFromServicesWebSite\ControllersFromServicesWebSite.csproj" />
<ProjectReference Include="..\WebSites\CorsWebSite\CorsWebSite.csproj" />
<ProjectReference Include="..\WebSites\DispatchingWebSite\DispatchingWebSite.csproj" />
<ProjectReference Include="..\WebSites\ErrorPageMiddlewareWebSite\ErrorPageMiddlewareWebSite.csproj" />
<ProjectReference Include="..\WebSites\FilesWebSite\FilesWebSite.csproj" />
<ProjectReference Include="..\WebSites\FormatterWebSite\FormatterWebSite.csproj" />

View File

@ -0,0 +1,25 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Admin
{
[Area("Admin")]
[Route("[area]/Users")]
public class UserManagementController : Controller
{
private readonly TestResponseGenerator _generator;
public UserManagementController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet("All")]
public IActionResult ListUsers()
{
return _generator.Generate("Admin/Users/All");
}
}
}

View File

@ -0,0 +1,25 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Areas.Order
{
[Area("Order")]
[Route("Order/[action]", Name = "[area]_[action]")]
public class OrderController : Controller
{
private readonly TestResponseGenerator _generator;
public OrderController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet]
public IActionResult GetOrder()
{
return _generator.Generate("/Order/GetOrder");
}
}
}

View File

@ -0,0 +1,30 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite
{
// This controller is reachable via traditional routing.
[Area("Travel")]
public class FlightController
{
private readonly TestResponseGenerator _generator;
public FlightController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult Index()
{
return _generator.Generate("/Travel/Flight", "/Travel/Flight/Index");
}
[HttpPost]
public IActionResult BuyTickets()
{
return _generator.Generate("/Travel/Flight/BuyTickets");
}
}
}

View File

@ -0,0 +1,29 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Travel
{
[Area("Travel")]
public class HomeController : Controller
{
private readonly TestResponseGenerator _generator;
public HomeController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult Index()
{
return _generator.Generate("/Travel", "/Travel/Home", "/Travel/Home/Index");
}
[HttpGet("ContosoCorp/AboutTravel")]
public IActionResult About()
{
return _generator.Generate();
}
}
}

View File

@ -0,0 +1,30 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite
{
[Area("Travel")]
[Route("ContosoCorp/Trains")]
public class RailController
{
private readonly TestResponseGenerator _generator;
public RailController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult Index()
{
return _generator.Generate("/ContosoCorp/Trains");
}
[HttpGet("CheckSchedule")]
public IActionResult Schedule()
{
return _generator.Generate("/ContosoCorp/Trains/Schedule");
}
}
}

View File

@ -0,0 +1,52 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
public class BanksController : Controller
{
private readonly TestResponseGenerator _generator;
public BanksController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet("Banks/[action]/{id}")]
[HttpGet("Bank/[action]/{id}")]
public ActionResult Get(int id)
{
return _generator.Generate(
Url.Action(),
Url.RouteUrl(new { }));
}
[AcceptVerbs("PUT", Route = "Bank")]
[HttpPatch("Bank")]
[AcceptVerbs("PUT", Route = "Bank/Update")]
[HttpPatch("Bank/Update")]
public ActionResult UpdateBank()
{
return _generator.Generate(
Url.Action(),
Url.RouteUrl(new { }));
}
[AcceptVerbs("PUT", "POST")]
[Route("Bank/Deposit")]
[Route("Bank/Deposit/{amount}")]
public ActionResult Deposit()
{
return _generator.Generate("/Bank/Deposit", "/Bank/Deposit/5");
}
[HttpPost]
[Route("Bank/Withdraw/{id}")]
public ActionResult Withdraw(int id)
{
return _generator.Generate("/Bank/Withdraw/5");
}
}
}

View File

@ -0,0 +1,29 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
// This controller contains actions mapped with a single controller-level route.
[Route("Blog/[action]/{postId?}")]
public class BlogController
{
private readonly TestResponseGenerator _generator;
public BlogController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult ShowPosts()
{
return _generator.Generate("/Blog/ShowPosts");
}
public IActionResult Edit(int postId)
{
return _generator.Generate("/Blog/Edit/" + postId);
}
}
}

View File

@ -0,0 +1,63 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
// A controller can define a route for all of the actions
// in it and give it a name for link generation purposes.
[Route("api/Company/{id}", Name = "Company")]
public class CompanyController : Controller
{
private readonly TestResponseGenerator _generator;
public CompanyController(TestResponseGenerator generator)
{
_generator = generator;
}
// An action with the same template will inherit the name
// from the controller.
[HttpGet]
public ActionResult Get(int id)
{
return _generator.Generate(Url.RouteUrl("Company", new { id = id }));
}
// Multiple actions can have the same named route as long
// as for a given Name, all the actions have the same template.
// That is, there can't be two link generation entries with same
// name and different templates.
[HttpPut]
public ActionResult Put(int id)
{
return _generator.Generate(Url.RouteUrl("Company", new { id = id }));
}
// Two actions can have the same template and each of them can have
// a different route name. That is, a given template can have multiple
// names associated with it.
[HttpDelete(Name = "RemoveCompany")]
public ActionResult Delete(int id)
{
return _generator.Generate(Url.RouteUrl("RemoveCompany", new { id = id }));
}
// An action that defines a non empty template doesn't inherit the name
// from the route on the controller .
[HttpGet("Employees")]
public ActionResult GetEmployees(int id)
{
return _generator.Generate(Url.RouteUrl(new { id = id }));
}
// An action that defines a non empty template doesn't inherit the name
// from the controller but can perfectly define its own name.
[HttpGet("Departments", Name = "Departments")]
public ActionResult GetDepartments(int id)
{
return _generator.Generate(Url.RouteUrl("Departments", new { id = id }));
}
}
}

View File

@ -0,0 +1,73 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
// This controller combines routes on the controller with routes on actions in a REST + navigation property
// style.
[Route("api/Employee")]
public class EmployeeController : Controller
{
private readonly TestResponseGenerator _generator;
public EmployeeController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult List()
{
return _generator.Generate("/api/Employee");
}
[AcceptVerbs("PUT", "PATCH")]
public IActionResult UpdateEmployee()
{
return _generator.Generate("/api/Employee");
}
[AcceptVerbs("PUT", "PATCH", Route = "Manager")]
public IActionResult UpdateManager()
{
return _generator.Generate("/api/Employee/Manager");
}
[HttpMerge("{id}")]
public IActionResult MergeEmployee(int id)
{
return _generator.Generate("/api/Employee/" + id);
}
[HttpGet("{id}")]
public IActionResult Get(int id)
{
return _generator.Generate("/api/Employee/" + id);
}
[HttpGet("{id}/Administrator")]
public IActionResult GetAdministrator(int id)
{
return _generator.Generate("/api/Employee/" + id + "/Administrator");
}
[HttpGet("~/Manager/{id}")]
public IActionResult GetManager(int id)
{
return _generator.Generate("/Manager/" + id);
}
[HttpDelete("{id}/Administrator")]
public IActionResult DeleteAdministrator(int id)
{
return _generator.Generate("/api/Employee/" + id + "/Administrator");
}
[Route("{id}/Salary")]
public IActionResult Salary(int id)
{
return _generator.Generate("/api/Employee/" + id + "/Salary");
}
}
}

View File

@ -0,0 +1,31 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
[Route("Friends")]
public class FriendsController : Controller
{
private readonly TestResponseGenerator _generator;
public FriendsController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet]
[HttpGet("{id}")]
public IActionResult Get([FromRoute]string id)
{
return _generator.Generate(id == null ? "/Friends" : $"/Friends/{id}");
}
[HttpDelete]
public IActionResult Delete()
{
return _generator.Generate("/Friends");
}
}
}

View File

@ -0,0 +1,39 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
// This controller is reachable via traditional routing.
public class HomeController : Controller
{
private readonly TestResponseGenerator _generator;
public HomeController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult Index()
{
return _generator.Generate("/", "/Home", "/Home/Index");
}
public IActionResult About()
{
// There are no urls that reach this action - it's hidden by an attribute route.
return _generator.Generate();
}
public IActionResult Contact()
{
return _generator.Generate("/Home/Contact");
}
public IActionResult OptionalPath(string path = "default")
{
return _generator.Generate("/Home/OptionalPath/" + path);
}
}
}

View File

@ -0,0 +1,53 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
[Route("api/v1/Maps", Name = "v1", Order = 1)]
[Route("api/v2/Maps")]
public class MapsController : Controller
{
private readonly TestResponseGenerator _generator;
public MapsController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet]
public ActionResult Get()
{
// Multiple attribute routes with name and order.
// We will always generate v2 routes except when
// we explicitly use "v1" to generate a v1 route.
return _generator.Generate(
Url.Action(),
Url.RouteUrl("v1"),
Url.RouteUrl(new { }));
}
[HttpPost("/api/v2/Maps")]
public ActionResult Post()
{
return _generator.Generate(
Url.Action(),
Url.RouteUrl(new { }));
}
[HttpPut("{id}")]
[HttpPatch("PartialUpdate/{id}")]
public ActionResult Update(int id)
{
// We will generate "/api/v2/Maps/PartialUpdate/{id}"
// in both cases, v1 routes will be discarded due to their
// Order and for v2 routes PartialUpdate has higher precedence.
// api/v1/Maps/{id} and api/v2/Maps/{id} will only match on PUT.
// api/v1/Maps/PartialUpdate/{id} and api/v2/Maps/PartialUpdate/{id} will only match on PATCH.
return _generator.Generate(
Url.Action(),
Url.RouteUrl(new { }));
}
}
}

View File

@ -0,0 +1,36 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
[Route("Order/[action]/{orderId?}", Name = "Order_[action]")]
public class OrderController : Controller
{
private readonly TestResponseGenerator _generator;
public OrderController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet]
public IActionResult Add(int orderId)
{
return _generator.Generate("/Order/Add/1");
}
[HttpPost]
public IActionResult Add()
{
return _generator.Generate("/Order/Add");
}
[HttpPut]
public IActionResult Edit(int orderId)
{
return _generator.Generate("/Order/Edit/1");
}
}
}

View File

@ -0,0 +1,43 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
// This controller contains only actions with individual attribute routes.
public class StoreController : Controller
{
private readonly TestResponseGenerator _generator;
public StoreController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet("Store/Shop/Products")]
public IActionResult ListProducts()
{
return _generator.Generate("/Store/Shop/Products");
}
// Intentionally designed to conflict with HomeController#About.
[HttpGet("Home/About")]
public IActionResult About()
{
return _generator.Generate("/Home/About");
}
[Route("Store/Shop/Orders")]
public IActionResult Orders()
{
return _generator.Generate("/Store/Shop/Orders");
}
[HttpGet("Store/Shop/Orders")]
public IActionResult GetOrders()
{
return _generator.Generate("/Store/Shop/Orders");
}
}
}

View File

@ -0,0 +1,72 @@
// 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 Microsoft.AspNetCore.Mvc;
namespace DispatchingWebSite.Controllers
{
[Route("/Teams", Order = 1)]
public class TeamController : Controller
{
private readonly TestResponseGenerator _generator;
public TeamController(TestResponseGenerator generator)
{
_generator = generator;
}
[HttpGet("/Team/{teamId}", Order = 2)]
public ActionResult GetTeam(int teamId)
{
return _generator.Generate("/Team/" + teamId);
}
[HttpGet("/Team/{teamId}")]
public ActionResult GetOrganization(int teamId)
{
return _generator.Generate("/Team/" + teamId);
}
[HttpGet("")]
public ActionResult GetTeams()
{
return _generator.Generate("/Teams");
}
[HttpGet("", Order = 0)]
public ActionResult GetOrganizations()
{
return _generator.Generate("/Teams");
}
[HttpGet("/Club/{clubId?}")]
public ActionResult GetClub()
{
return Content(Url.Action(), "text/plain");
}
[HttpGet("/Organization/{clubId?}", Order = 1)]
public ActionResult GetClub(int clubId)
{
return Content(Url.Action(), "text/plain");
}
[HttpGet("AllTeams")]
public ActionResult GetAllTeams()
{
return Content(Url.Action(), "text/plain");
}
[HttpGet("AllOrganizations", Order = 0)]
public ActionResult GetAllTeams(int notRelevant)
{
return Content(Url.Action(), "text/plain");
}
[HttpGet("/TeamName/{*Name=DefaultName}/")]
public ActionResult GetTeam(string name)
{
return _generator.Generate("/TeamName/" + name);
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>$(StandardTestWebsiteTfms)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Mvc\Microsoft.AspNetCore.Mvc.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
</ItemGroup>
</Project>

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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Routing;
namespace DispatchingWebSite
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class HttpMergeAttribute : Attribute, IActionHttpMethodProvider, IRouteTemplateProvider
{
private static readonly IEnumerable<string> _supportedMethods = new[] { "MERGE" };
public HttpMergeAttribute(string template)
{
Template = template;
}
public IEnumerable<string> HttpMethods
{
get { return _supportedMethods; }
}
/// <inheritdoc />
public string Template { get; private set; }
/// <inheritdoc />
public int? Order { get; set; }
/// <inheritdoc />
public string Name { get; set; }
}
}

View File

@ -0,0 +1,78 @@
// 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.IO;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
namespace DispatchingWebSite
{
public class Startup
{
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddDispatcher();
services.AddMvc();
services.AddScoped<TestResponseGenerator>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}
public void Configure(IApplicationBuilder app)
{
app.UseDispatcher();
//app.UseMvc(routes =>
//{
// routes.MapAreaRoute(
// "flightRoute",
// "adminRoute",
// "{area:exists}/{controller}/{action}",
// new { controller = "Home", action = "Index" },
// new { area = "Travel" });
// routes.MapRoute(
// "ActionAsMethod",
// "{controller}/{action}",
// defaults: new { controller = "Home", action = "Index" });
// routes.MapRoute(
// "RouteWithOptionalSegment",
// "{controller}/{action}/{path?}");
//});
app.UseEndpoint();
}
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
})
.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseKestrel()
.UseIISIntegration();
}
}

View File

@ -0,0 +1,61 @@
// 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 System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
namespace DispatchingWebSite
{
// Generates a response based on the expected URL and action context
public class TestResponseGenerator
{
private readonly ActionContext _actionContext;
private readonly IUrlHelperFactory _urlHelperFactory;
public TestResponseGenerator(IActionContextAccessor contextAccessor, IUrlHelperFactory urlHelperFactory)
{
_urlHelperFactory = urlHelperFactory;
_actionContext = contextAccessor.ActionContext;
if (_actionContext == null)
{
throw new InvalidOperationException("ActionContext should not be null here.");
}
}
public JsonResult Generate(params string[] expectedUrls)
{
var link = (string)null;
var query = _actionContext.HttpContext.Request.Query;
if (query.ContainsKey("link"))
{
var values = query
.Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller")
.ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]);
var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContext);
link = urlHelper.Action(query["link_action"], query["link_controller"], values);
}
var attributeRoutingInfo = _actionContext.ActionDescriptor.AttributeRouteInfo;
return new JsonResult(new
{
expectedUrls = expectedUrls,
actualUrl = _actionContext.HttpContext.Request.Path.Value,
routeName = attributeRoutingInfo == null ? null : attributeRoutingInfo.Name,
routeValues = new Dictionary<string, object>(_actionContext.RouteData.Values),
action = ((ControllerActionDescriptor) _actionContext.ActionDescriptor).ActionName,
controller = ((ControllerActionDescriptor)_actionContext.ActionDescriptor).ControllerName,
link,
});
}
}
}

View File

@ -0,0 +1,4 @@
DispatchingWebSite
===
This web site illustrates how to use conventional and attribute dispatching.