Merge release/2.2

This commit is contained in:
James Newton-King 2018-07-17 22:41:56 +12:00
parent 11a9bafeb4
commit 737464eafa
No known key found for this signature in database
GPG Key ID: 0A66B2F456BF5526
49 changed files with 1069 additions and 666 deletions

View File

@ -12,11 +12,12 @@ Microsoft.AspNetCore.Mvc.IActionResult</Description>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Routing.Abstractions" Version="$(MicrosoftAspNetCoreRoutingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.CopyOnWriteDictionary.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="$(MicrosoftNetHttpHeadersPackageVersion)" />
</ItemGroup>
<ItemGroup Label="Sources packages">
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -3,5 +3,35 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ApiExplorer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Cors, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.DataAnnotations, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Json, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Xml, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Localization, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Testing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ViewFeatures, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ApiExplorer.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Cors.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.DataAnnotations.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Json.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Xml.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Localization.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ViewFeatures.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Views.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@ -10,10 +10,6 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Core\Microsoft.AspNetCore.Mvc.Core.csproj" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -7,13 +7,13 @@ using System.Linq;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
using Microsoft.Net.Http.Headers;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc
{

View File

@ -8,11 +8,11 @@ using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Internal
{

View File

@ -6,13 +6,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Template;
using Microsoft.AspNetCore.Routing.Tree;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Internal
{

View File

@ -10,9 +10,9 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Routing;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Internal
{

View File

@ -7,11 +7,11 @@ using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Internal
{

View File

@ -5,10 +5,10 @@ using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Internal
{

View File

@ -293,6 +293,25 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return invoker.InvokeAsync();
};
var metadataCollection = BuildEndpointMetadata(action, routeName, source);
var endpoint = new MatcherEndpoint(
next => invokerDelegate,
template,
new RouteValueDictionary(nonInlineDefaults),
new RouteValueDictionary(action.RouteValues),
order,
metadataCollection,
action.DisplayName);
// Use defaults after the endpoint is created as it merges both the inline and
// non-inline defaults into one.
EnsureRequiredValuesInDefaults(endpoint.RequiredValues, endpoint.Defaults);
return endpoint;
}
private static EndpointMetadataCollection BuildEndpointMetadata(ActionDescriptor action, string routeName, object source)
{
var metadata = new List<object>();
// REVIEW: Used for debugging. Consider removing before release
metadata.Add(source);
@ -312,30 +331,27 @@ namespace Microsoft.AspNetCore.Mvc.Internal
if (action.ActionConstraints != null && action.ActionConstraints.Count > 0)
{
// REVIEW: What is the best way to pick up endpoint constraints of an ActionDescriptor?
// Currently they need to implement IActionConstraintMetadata
foreach (var actionConstraint in action.ActionConstraints)
{
if (actionConstraint is HttpMethodActionConstraint httpMethodActionConstraint)
{
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
if (!metadata.Contains(actionConstraint))
{
metadata.Add(actionConstraint);
}
}
}
}
var metadataCollection = new EndpointMetadataCollection(metadata);
var endpoint = new MatcherEndpoint(
next => invokerDelegate,
template,
new RouteValueDictionary(nonInlineDefaults),
new RouteValueDictionary(action.RouteValues),
order,
metadataCollection,
action.DisplayName);
// Use defaults after the endpoint is created as it merges both the inline and
// non-inline defaults into one.
EnsureRequiredValuesInDefaults(endpoint.RequiredValues, endpoint.Defaults);
return endpoint;
return metadataCollection;
}
// Ensure required values are a subset of defaults

View File

@ -24,24 +24,27 @@ Microsoft.AspNetCore.Mvc.RouteAttribute</Description>
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(MicrosoftAspNetCoreHostingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(MicrosoftAspNetCoreHttpPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="$(MicrosoftAspNetCoreHttpExtensionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.RangeHelper.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreRangeHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.ResponseCaching.Abstractions" Version="$(MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="$(MicrosoftAspNetCoreRoutingPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="$(MicrosoftExtensionsFileProvidersAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ObjectMethodExecutor.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ParameterDefaultValue.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyActivator.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyActivatorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.SecurityHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsSecurityHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.TypeNameHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsTypeNameHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ValueStopwatch.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsValueStopwatchSourcesPackageVersion)" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="$(SystemDiagnosticsDiagnosticSourcePackageVersion)" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="$(SystemThreadingTasksExtensionsPackageVersion)" />
</ItemGroup>
</Project>
<ItemGroup Label="Sources packages">
<PackageReference Include="Microsoft.AspNetCore.ChunkingCookieManager.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.CopyOnWriteDictionary.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ObjectMethodExecutor.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ParameterDefaultValue.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyActivator.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyActivatorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.RangeHelper.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreRangeHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.SecurityHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsSecurityHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.TypeNameHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsTypeNameHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ValueStopwatch.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsValueStopwatchSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -4,8 +4,36 @@
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Formatters;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: TypeForwardedTo(typeof(InputFormatterException))]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ApiExplorer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Cors, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.DataAnnotations, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Json, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Xml, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Localization, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Testing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ViewFeatures, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ApiExplorer.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Cors.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.DataAnnotations.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Json.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Formatters.Xml.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Localization.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.ViewFeatures.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Views.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: TypeForwardedTo(typeof(InputFormatterException))]

View File

@ -11,8 +11,6 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Core\Microsoft.AspNetCore.Mvc.Core.csproj" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.CopyOnWriteDictionary.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="$(MicrosoftExtensionsLocalizationPackageVersion)" />
<PackageReference Include="System.ComponentModel.Annotations" Version="$(SystemComponentModelAnnotationsPackageVersion)" />
</ItemGroup>

View File

@ -10,8 +10,5 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Core\Microsoft.AspNetCore.Mvc.Core.csproj" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -17,7 +17,6 @@ Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer</Description>
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="$(MicrosoftAspNetCoreLocalizationPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="$(MicrosoftExtensionsLocalizationPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,9 @@
using System;
namespace Microsoft.AspNetCore.Mvc.Razor
{
internal interface IModelTypeProvider
{
Type GetModelType();
}
}

View File

@ -19,10 +19,6 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisCSharpPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Composite" Version="$(MicrosoftExtensionsFileProvidersCompositePackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyActivator.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyActivatorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
</ItemGroup>
<ItemGroup>

View File

@ -3,5 +3,7 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Mvc.Razor
{
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
{
// Name of the "public TModel Model" property on RazorPage<TModel>
private const string ModelPropertyName = "Model";
private readonly ConcurrentDictionary<Type, RazorPagePropertyActivator> _activationInfo;
private readonly ConcurrentDictionary<CacheKey, RazorPagePropertyActivator> _activationInfo;
private readonly IModelMetadataProvider _metadataProvider;
// Value accessors for common singleton properties activated in a RazorPage.
@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
HtmlEncoder htmlEncoder,
IModelExpressionProvider modelExpressionProvider)
{
_activationInfo = new ConcurrentDictionary<Type, RazorPagePropertyActivator>();
_activationInfo = new ConcurrentDictionary<CacheKey, RazorPagePropertyActivator>();
_metadataProvider = metadataProvider;
_propertyAccessors = new RazorPagePropertyActivator.PropertyValueAccessors
@ -62,26 +63,76 @@ namespace Microsoft.AspNetCore.Mvc.Razor
throw new ArgumentNullException(nameof(context));
}
var propertyActivator = GetOrAddCacheEntry(page);
propertyActivator.Activate(page, context);
}
internal RazorPagePropertyActivator GetOrAddCacheEntry(IRazorPage page)
{
var pageType = page.GetType();
RazorPagePropertyActivator propertyActivator;
if (!_activationInfo.TryGetValue(pageType, out propertyActivator))
Type providedModelType = null;
if (page is IModelTypeProvider modelTypeProvider)
{
providedModelType = modelTypeProvider.GetModelType();
}
// We only need to vary by providedModelType since it varies at runtime. Defined model type
// is synonymous with the pageType and consequently does not need to be accounted for in the cache key.
var cacheKey = new CacheKey(pageType, providedModelType);
if (!_activationInfo.TryGetValue(cacheKey, out var propertyActivator))
{
// Look for a property named "Model". If it is non-null, we'll assume this is
// the equivalent of TModel Model property on RazorPage<TModel>.
//
// Otherwise if we don't have a model property the activator will just skip setting
// the view data.
var modelType = pageType.GetRuntimeProperty(ModelPropertyName)?.PropertyType;
var modelType = providedModelType;
if (modelType == null)
{
modelType = pageType.GetRuntimeProperty(ModelPropertyName)?.PropertyType;
}
propertyActivator = new RazorPagePropertyActivator(
pageType,
modelType,
_metadataProvider,
_propertyAccessors);
propertyActivator = _activationInfo.GetOrAdd(pageType, propertyActivator);
propertyActivator = _activationInfo.GetOrAdd(cacheKey, propertyActivator);
}
propertyActivator.Activate(page, context);
return propertyActivator;
}
private readonly struct CacheKey : IEquatable<CacheKey>
{
public CacheKey(Type pageType, Type providedModelType)
{
PageType = pageType;
ProvidedModelType = providedModelType;
}
public Type PageType { get; }
public Type ProvidedModelType { get; }
public bool Equals(CacheKey other)
{
return PageType == other.PageType &&
ProvidedModelType == other.ProvidedModelType;
}
public override int GetHashCode()
{
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(PageType);
if (ProvidedModelType != null)
{
hashCodeCombiner.Add(ProvidedModelType);
}
return hashCodeCombiner.CombinedHash;
}
}
}
}

View File

@ -96,6 +96,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor
/// </summary>
public IReadOnlyList<IRazorPage> ViewStartPages { get; }
internal Action<IRazorPage, ViewContext> OnAfterPageActivated { get; set; }
/// <inheritdoc />
public virtual async Task RenderAsync(ViewContext context)
{
@ -167,6 +169,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor
page.ViewContext = context;
_pageActivator.Activate(page, context);
OnAfterPageActivated?.Invoke(page, context);
_diagnosticSource.BeforeViewPage(page, context);
try

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Resources = Microsoft.AspNetCore.Mvc.RazorPages.Resources;
namespace Microsoft.Extensions.DependencyInjection
{

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Resources = Microsoft.AspNetCore.Mvc.RazorPages.Resources;
namespace Microsoft.Extensions.DependencyInjection
{

View File

@ -76,13 +76,29 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
}
var viewContext = result.Page.ViewContext;
var pageAdapter = new RazorPageAdapter(result.Page, pageContext.ActionDescriptor.DeclaredModelTypeInfo);
viewContext.View = new RazorView(
_razorViewEngine,
_razorPageActivator,
viewStarts,
new RazorPageAdapter(result.Page),
pageAdapter,
_htmlEncoder,
_diagnosticSource);
_diagnosticSource)
{
OnAfterPageActivated = (page, currentViewContext) =>
{
if (page != pageAdapter)
{
return;
}
// ViewContext is always activated with the "right" ViewData<T> type.
// Copy that over to the PageContext since PageContext.ViewData is exposed
// as the ViewData property on the Page that the user works with.
pageContext.ViewData = currentViewContext.ViewData;
},
};
return ExecuteAsync(viewContext, result.ContentType, result.StatusCode);
}

View File

@ -14,10 +14,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
//
// The page gets activated before handler methods run, but the RazorView will also activate
// each page.
public class RazorPageAdapter : IRazorPage
public class RazorPageAdapter : IRazorPage, IModelTypeProvider
{
private readonly RazorPageBase _page;
private readonly Type _modelType;
[Obsolete("This constructor is obsolete and will be removed in a future version.")]
public RazorPageAdapter(RazorPageBase page)
{
if (page == null)
@ -28,6 +30,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
_page = page;
}
public RazorPageAdapter(RazorPageBase page, Type modelType)
{
_page = page ?? throw new ArgumentNullException(nameof(page));
_modelType = modelType ?? throw new ArgumentNullException(nameof(modelType));
}
public ViewContext ViewContext
{
get { return _page.ViewContext; }
@ -75,5 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
return _page.ExecuteAsync();
}
Type IModelTypeProvider.GetModelType() => _modelType;
}
}

View File

@ -10,16 +10,6 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Razor\Microsoft.AspNetCore.Mvc.Razor.csproj" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.CopyOnWriteDictionary.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ParameterDefaultValue.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyActivator.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyActivatorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
</ItemGroup>
<ItemGroup>
<Folder Include="Filters\" />
</ItemGroup>
</Project>

View File

@ -19,8 +19,6 @@
<PackageReference Include="Microsoft.AspNetCore.Routing.Abstractions" Version="$(MicrosoftAspNetCoreRoutingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="$(MicrosoftExtensionsFileSystemGlobbingPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="$(MicrosoftExtensionsPrimitivesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -19,16 +19,8 @@ Microsoft.AspNetCore.Mvc.ViewComponent</Description>
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Formatters.Json\Microsoft.AspNetCore.Mvc.Formatters.Json.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="$(MicrosoftAspNetCoreAntiforgeryPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.ChunkingCookieManager.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.Abstractions" Version="$(MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Html.Abstractions" Version="$(MicrosoftAspNetCoreHtmlAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.CopyOnWriteDictionary.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ObjectMethodExecutor.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyActivator.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyActivatorSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ValueStopwatch.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsValueStopwatchSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.WebEncoders" Version="$(MicrosoftExtensionsWebEncodersPackageVersion)" />
<PackageReference Include="Newtonsoft.Json.Bson" Version="$(NewtonsoftJsonBsonPackageVersion)" />
</ItemGroup>

View File

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Test;
using Resources = Microsoft.AspNetCore.Mvc.DataAnnotations.Test.Resources;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{

View File

@ -607,6 +607,22 @@ Hello from /Pages/Shared/";
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task ViewDataSetInViewStart_IsAvailableToPage()
{
// Arrange & Act
var document = await Client.GetHtmlDocumentAsync("/ViewData/ViewDataSetInViewStart");
// Assert
var valueSetInViewStart = document.RequiredQuerySelector("#valuefromviewstart").TextContent;
var valueSetInPageModel = document.RequiredQuerySelector("#valuefrompagemodel").TextContent;
var valueSetInPage = document.RequiredQuerySelector("#valuefrompage").TextContent;
Assert.Equal("Value from _ViewStart", valueSetInViewStart);
Assert.Equal("Value from Page Model", valueSetInPageModel);
Assert.Equal("Value from Page", valueSetInPage);
}
private async Task AddAntiforgeryHeadersAsync(HttpRequestMessage request)
{
var response = await Client.GetAsync(request.RequestUri);

View File

@ -0,0 +1,13 @@
// 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.
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
public class VersioningDispatchingTests : VersioningTestsBase<VersioningWebSite.StartupWithDispatching>
{
public VersioningDispatchingTests(MvcTestFixture<VersioningWebSite.StartupWithDispatching> fixture)
: base(fixture)
{
}
}
}

View File

@ -1,562 +1,13 @@
// 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.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
public class VersioningTests : IClassFixture<MvcTestFixture<VersioningWebSite.Startup>>
public class VersioningTests : VersioningTestsBase<VersioningWebSite.Startup>
{
public VersioningTests(MvcTestFixture<VersioningWebSite.Startup> fixture)
: base(fixture)
{
Client = fixture.CreateDefaultClient();
}
public HttpClient Client { get; }
[Theory]
[InlineData("1")]
[InlineData("2")]
public async Task AttributeRoutedAction_WithVersionedRoutes_IsNotAmbiguous(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/Addresses?version=" + version);
// 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.Contains("api/addresses", result.ExpectedUrls);
Assert.Equal("Address", result.Controller);
Assert.Equal("GetV" + version, result.Action);
}
[Theory]
[InlineData("1")]
[InlineData("2")]
public async Task AttributeRoutedAction_WithAmbiguousVersionedRoutes_CanBeDisambiguatedUsingOrder(string version)
{
// Arrange
var query = "?version=" + version;
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/Addresses/All" + query);
// 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.Contains("/api/addresses/all?version=" + version, result.ExpectedUrls);
Assert.Equal("Address", result.Controller);
Assert.Equal("GetAllV" + version, result.Action);
}
[Fact]
public async Task VersionedApi_CanReachV1Operations_OnTheSameController_WithNoVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets");
// 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("Tickets", result.Controller);
Assert.Equal("Get", result.Action);
Assert.DoesNotContain("id", result.RouteValues.Keys);
}
[Fact]
public async Task VersionedApi_CanReachV1Operations_OnTheSameController_WithVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets?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("Tickets", result.Controller);
Assert.Equal("Get", result.Action);
}
[Fact]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheSameController()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets/5");
// 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("Tickets", result.Controller);
Assert.Equal("GetById", result.Action);
}
[Fact]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheSameController_WithVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets/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("Tickets", result.Controller);
Assert.Equal("GetById", result.Action);
Assert.NotEmpty(result.RouteValues);
Assert.Contains(
new KeyValuePair<string, object>("id", "5"),
result.RouteValues);
}
[Theory]
[InlineData("2")]
[InlineData("3")]
[InlineData("4")]
public async Task VersionedApi_CanReachOtherVersionOperations_OnTheSameController(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Tickets?version=" + version);
// 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("Tickets", result.Controller);
Assert.Equal("Post", result.Action);
Assert.NotEmpty(result.RouteValues);
Assert.DoesNotContain(
new KeyValuePair<string, object>("id", "5"),
result.RouteValues);
}
[Fact]
public async Task VersionedApi_CanNotReachOtherVersionOperations_OnTheSameController_WithNoVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Tickets");
// Act
var response = await Client.SendAsync(message);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
var body = await response.Content.ReadAsByteArrayAsync();
Assert.Empty(body);
}
[Theory]
[InlineData("PUT", "Put", "2")]
[InlineData("PUT", "Put", "3")]
[InlineData("PUT", "Put", "4")]
[InlineData("DELETE", "Delete", "2")]
[InlineData("DELETE", "Delete", "3")]
[InlineData("DELETE", "Delete", "4")]
public async Task VersionedApi_CanReachOtherVersionOperationsWithParameters_OnTheSameController(
string method,
string action,
string version)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Tickets/5?version=" + version);
// 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("Tickets", result.Controller);
Assert.Equal(action, result.Action);
Assert.NotEmpty(result.RouteValues);
Assert.Contains(
new KeyValuePair<string, object>("id", "5"),
result.RouteValues);
}
[Theory]
[InlineData("PUT")]
[InlineData("DELETE")]
public async Task VersionedApi_CanNotReachOtherVersionOperationsWithParameters_OnTheSameController_WithNoVersionSpecified(string method)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Tickets/5");
// Act
var response = await Client.SendAsync(message);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
var body = await response.Content.ReadAsByteArrayAsync();
Assert.Empty(body);
}
[Theory]
[InlineData("3")]
[InlineData("4")]
[InlineData("5")]
public async Task VersionedApi_CanUseOrderToDisambiguate_OverlappingVersionRanges(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Books?version=" + version);
// 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("Books", result.Controller);
Assert.Equal("GetBreakingChange", result.Action);
}
[Theory]
[InlineData("1")]
[InlineData("2")]
[InlineData("6")]
public async Task VersionedApi_OverlappingVersionRanges_FallsBackToLowerOrderAction(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Books?version=" + version);
// 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("Books", result.Controller);
Assert.Equal("Get", result.Action);
}
[Theory]
[InlineData("GET", "Get")]
[InlineData("POST", "Post")]
public async Task VersionedApi_CanReachV1Operations_OnTheOriginalController_WithNoVersionSpecified(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies");
// 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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Theory]
[InlineData("GET", "Get")]
[InlineData("POST", "Post")]
public async Task VersionedApi_CanReachV1Operations_OnTheOriginalController_WithVersionSpecified(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies?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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Theory]
[InlineData("GET", "GetById")]
[InlineData("PUT", "Put")]
[InlineData("DELETE", "Delete")]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheOriginalController(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies/5");
// 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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Theory]
[InlineData("GET", "GetById")]
[InlineData("DELETE", "Delete")]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheOriginalController_WithVersionSpecified(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies/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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Fact]
public async Task VersionedApi_CanReachOtherVersionOperationsWithParameters_OnTheV2Controller()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Put, "http://localhost/Movies/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("MoviesV2", result.Controller);
Assert.Equal("Put", result.Action);
Assert.NotEmpty(result.RouteValues);
}
[Theory]
[InlineData("v1/Pets")]
[InlineData("v2/Pets")]
public async Task VersionedApi_CanHaveTwoRoutesWithVersionOnTheUrl_OnTheSameAction(string url)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/" + url);
// 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("Pets", result.Controller);
Assert.Equal("Get", result.Action);
}
[Theory]
[InlineData("v1/Pets/5", "V1")]
[InlineData("v2/Pets/5", "V2")]
public async Task VersionedApi_CanHaveTwoRoutesWithVersionOnTheUrl_OnDifferentActions(string url, string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/" + url);
// 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("Pets", result.Controller);
Assert.Equal("Get" + version, result.Action);
}
[Theory]
[InlineData("v1/Pets", "V1")]
[InlineData("v2/Pets", "V2")]
public async Task VersionedApi_CanHaveTwoRoutesWithVersionOnTheUrl_OnDifferentActions_WithInlineConstraint(string url, string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/" + url);
// 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("Pets", result.Controller);
Assert.Equal("Post" + version, result.Action);
}
[Theory]
[InlineData("Customers/5", "?version=1", "Get")]
[InlineData("Customers/5", "?version=2", "Get")]
[InlineData("Customers/5", "?version=3", "GetV3ToV5")]
[InlineData("Customers/5", "?version=4", "GetV3ToV5")]
[InlineData("Customers/5", "?version=5", "GetV3ToV5")]
public async Task VersionedApi_CanProvideVersioningInformation_UsingPlainActionConstraint(string url, string query, string actionName)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/" + url + query);
// 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(actionName, result.Action);
}
[Fact]
public async Task VersionedApi_ConstraintOrder_IsRespected()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/" + "Customers?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("AnyV2OrHigher", result.Action);
}
[Fact]
public 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("Delete", result.Action);
}
[Theory]
[InlineData("1")]
[InlineData("2")]
public async Task VersionedApi_MultipleVersionsUsingAttributeRouting_OnTheSameMethod(string version)
{
// Arrange
var path = "/" + version + "/Vouchers?version=" + version;
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost" + path);
// 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("Vouchers", result.Controller);
Assert.Equal("GetVouchersMultipleVersions", result.Action);
var actualUrl = Assert.Single(result.ExpectedUrls);
Assert.Equal(path, actualUrl);
}
private class RoutingResult
{
public string[] ExpectedUrls { get; set; }
public string ActualUrl { get; set; }
public Dictionary<string, object> RouteValues { get; set; }
public string RouteName { get; set; }
public string Action { get; set; }
public string Controller { get; set; }
public string Link { get; set; }
}
}
}

View File

@ -0,0 +1,568 @@
// 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.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Newtonsoft.Json;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
public abstract class VersioningTestsBase<TStartup> : IClassFixture<MvcTestFixture<TStartup>> where TStartup : class
{
protected VersioningTestsBase(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("1")]
[InlineData("2")]
public async Task AttributeRoutedAction_WithVersionedRoutes_IsNotAmbiguous(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/Addresses?version=" + version);
// 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.Contains("api/addresses", result.ExpectedUrls);
Assert.Equal("Address", result.Controller);
Assert.Equal("GetV" + version, result.Action);
}
[Theory]
[InlineData("1")]
[InlineData("2")]
public async Task AttributeRoutedAction_WithAmbiguousVersionedRoutes_CanBeDisambiguatedUsingOrder(string version)
{
// Arrange
var query = "?version=" + version;
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/Addresses/All" + query);
// 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.Contains("/api/addresses/all?version=" + version, result.ExpectedUrls);
Assert.Equal("Address", result.Controller);
Assert.Equal("GetAllV" + version, result.Action);
}
[Fact]
public async Task VersionedApi_CanReachV1Operations_OnTheSameController_WithNoVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets");
// 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("Tickets", result.Controller);
Assert.Equal("Get", result.Action);
Assert.DoesNotContain("id", result.RouteValues.Keys);
}
[Fact]
public async Task VersionedApi_CanReachV1Operations_OnTheSameController_WithVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets?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("Tickets", result.Controller);
Assert.Equal("Get", result.Action);
}
[Fact]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheSameController()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets/5");
// 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("Tickets", result.Controller);
Assert.Equal("GetById", result.Action);
}
[Fact]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheSameController_WithVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Tickets/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("Tickets", result.Controller);
Assert.Equal("GetById", result.Action);
Assert.NotEmpty(result.RouteValues);
Assert.Contains(
new KeyValuePair<string, object>("id", "5"),
result.RouteValues);
}
[Theory]
[InlineData("2")]
[InlineData("3")]
[InlineData("4")]
public async Task VersionedApi_CanReachOtherVersionOperations_OnTheSameController(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Tickets?version=" + version);
// 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("Tickets", result.Controller);
Assert.Equal("Post", result.Action);
Assert.NotEmpty(result.RouteValues);
Assert.DoesNotContain(
new KeyValuePair<string, object>("id", "5"),
result.RouteValues);
}
[Fact]
public async Task VersionedApi_CanNotReachOtherVersionOperations_OnTheSameController_WithNoVersionSpecified()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Tickets");
// Act
var response = await Client.SendAsync(message);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
var body = await response.Content.ReadAsByteArrayAsync();
Assert.Empty(body);
}
[Theory]
[InlineData("PUT", "Put", "2")]
[InlineData("PUT", "Put", "3")]
[InlineData("PUT", "Put", "4")]
[InlineData("DELETE", "Delete", "2")]
[InlineData("DELETE", "Delete", "3")]
[InlineData("DELETE", "Delete", "4")]
public async Task VersionedApi_CanReachOtherVersionOperationsWithParameters_OnTheSameController(
string method,
string action,
string version)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Tickets/5?version=" + version);
// 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("Tickets", result.Controller);
Assert.Equal(action, result.Action);
Assert.NotEmpty(result.RouteValues);
Assert.Contains(
new KeyValuePair<string, object>("id", "5"),
result.RouteValues);
}
[Theory]
[InlineData("PUT")]
[InlineData("DELETE")]
public async Task VersionedApi_CanNotReachOtherVersionOperationsWithParameters_OnTheSameController_WithNoVersionSpecified(string method)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Tickets/5");
// Act
var response = await Client.SendAsync(message);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
var body = await response.Content.ReadAsByteArrayAsync();
Assert.Empty(body);
}
[Theory]
[InlineData("3")]
[InlineData("4")]
[InlineData("5")]
public async Task VersionedApi_CanUseOrderToDisambiguate_OverlappingVersionRanges(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Books?version=" + version);
// 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("Books", result.Controller);
Assert.Equal("GetBreakingChange", result.Action);
}
[Theory]
[InlineData("1")]
[InlineData("2")]
[InlineData("6")]
public async Task VersionedApi_OverlappingVersionRanges_FallsBackToLowerOrderAction(string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Books?version=" + version);
// 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("Books", result.Controller);
Assert.Equal("Get", result.Action);
}
[Theory]
[InlineData("GET", "Get")]
[InlineData("POST", "Post")]
public async Task VersionedApi_CanReachV1Operations_OnTheOriginalController_WithNoVersionSpecified(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies");
// 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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Theory]
[InlineData("GET", "Get")]
[InlineData("POST", "Post")]
public async Task VersionedApi_CanReachV1Operations_OnTheOriginalController_WithVersionSpecified(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies?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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Theory]
[InlineData("GET", "GetById")]
[InlineData("PUT", "Put")]
[InlineData("DELETE", "Delete")]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheOriginalController(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies/5");
// 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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Theory]
[InlineData("GET", "GetById")]
[InlineData("DELETE", "Delete")]
public async Task VersionedApi_CanReachV1OperationsWithParameters_OnTheOriginalController_WithVersionSpecified(string method, string action)
{
// Arrange
var message = new HttpRequestMessage(new HttpMethod(method), "http://localhost/Movies/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("Movies", result.Controller);
Assert.Equal(action, result.Action);
}
[Fact]
public async Task VersionedApi_CanReachOtherVersionOperationsWithParameters_OnTheV2Controller()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Put, "http://localhost/Movies/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("MoviesV2", result.Controller);
Assert.Equal("Put", result.Action);
Assert.NotEmpty(result.RouteValues);
}
[Theory]
[InlineData("v1/Pets")]
[InlineData("v2/Pets")]
public async Task VersionedApi_CanHaveTwoRoutesWithVersionOnTheUrl_OnTheSameAction(string url)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/" + url);
// 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("Pets", result.Controller);
Assert.Equal("Get", result.Action);
}
[Theory]
[InlineData("v1/Pets/5", "V1")]
[InlineData("v2/Pets/5", "V2")]
public async Task VersionedApi_CanHaveTwoRoutesWithVersionOnTheUrl_OnDifferentActions(string url, string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/" + url);
// 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("Pets", result.Controller);
Assert.Equal("Get" + version, result.Action);
}
[Theory]
[InlineData("v1/Pets", "V1")]
[InlineData("v2/Pets", "V2")]
public async Task VersionedApi_CanHaveTwoRoutesWithVersionOnTheUrl_OnDifferentActions_WithInlineConstraint(string url, string version)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/" + url);
// 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("Pets", result.Controller);
Assert.Equal("Post" + version, result.Action);
}
[Theory]
[InlineData("Customers/5", "?version=1", "Get")]
[InlineData("Customers/5", "?version=2", "Get")]
[InlineData("Customers/5", "?version=3", "GetV3ToV5")]
[InlineData("Customers/5", "?version=4", "GetV3ToV5")]
[InlineData("Customers/5", "?version=5", "GetV3ToV5")]
public async Task VersionedApi_CanProvideVersioningInformation_UsingPlainActionConstraint(string url, string query, string actionName)
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost/" + url + query);
// 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(actionName, result.Action);
}
[Fact]
public async Task VersionedApi_ConstraintOrder_IsRespected()
{
// Arrange
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/" + "Customers?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("AnyV2OrHigher", result.Action);
}
[Fact]
public 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("Delete", result.Action);
}
[Theory]
[InlineData("1")]
[InlineData("2")]
public async Task VersionedApi_MultipleVersionsUsingAttributeRouting_OnTheSameMethod(string version)
{
// Arrange
var path = "/" + version + "/Vouchers?version=" + version;
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost" + path);
// 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("Vouchers", result.Controller);
Assert.Equal("GetVouchersMultipleVersions", result.Action);
var actualUrl = Assert.Single(result.ExpectedUrls);
Assert.Equal(path, actualUrl);
}
private class RoutingResult
{
public string[] ExpectedUrls { get; set; }
public string ActualUrl { get; set; }
public Dictionary<string, object> RouteValues { get; set; }
public string RouteName { get; set; }
public string Action { get; set; }
public string Controller { get; set; }
public string Link { get; set; }
}
}
}

View File

@ -165,6 +165,69 @@ namespace Microsoft.AspNetCore.Mvc.Razor
Assert.Throws<InvalidCastException>(() => activator.Activate(instance, viewContext));
}
[Fact]
public void Activate_UsesModelFromModelTypeProvider()
{
// Arrange
var activator = CreateActivator();
var viewData = new ViewDataDictionary<object>(MetadataProvider, new ModelStateDictionary())
{
{ "key", "value" },
};
var viewContext = CreateViewContext(viewData);
var page = new ModelTypeProviderRazorPage();
// Act
activator.Activate(page, viewContext);
// Assert
Assert.Same(viewContext.ViewData, page.ViewData);
Assert.NotSame(viewData, viewContext.ViewData);
Assert.IsType<ViewDataDictionary<Guid>>(viewContext.ViewData);
Assert.Equal("value", viewContext.ViewData["key"]);
}
[Fact]
public void GetOrAddCacheEntry_CachesPages()
{
// Arrange
var activator = CreateActivator();
var page = new TestRazorPage();
// Act
var result1 = activator.GetOrAddCacheEntry(page);
var result2 = activator.GetOrAddCacheEntry(page);
// Assert
Assert.Same(result1, result2);
}
[Fact]
public void GetOrAddCacheEntry_VariesByModelType_IfPageIsModelTypeProvider()
{
// Arrange
var activator = CreateActivator();
var page = new ModelTypeProviderRazorPage();
// Act - 1
var result1 = activator.GetOrAddCacheEntry(page);
var result2 = activator.GetOrAddCacheEntry(page);
// Assert - 1
Assert.Same(result1, result2);
// Act - 2
page.ModelType = typeof(string);
var result3 = activator.GetOrAddCacheEntry(page);
var result4 = activator.GetOrAddCacheEntry(page);
// Assert - 2
Assert.Same(result3, result4);
Assert.NotSame(result1, result3);
}
private RazorPageActivator CreateActivator()
{
return new RazorPageActivator(MetadataProvider, UrlHelperFactory, JsonHelper, DiagnosticSource, HtmlEncoder, ModelExpressionProvider);
@ -225,6 +288,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor
}
}
private class ModelTypeProviderRazorPage : RazorPage, IModelTypeProvider
{
[RazorInject]
public ViewDataDictionary ViewData { get; set; }
public Type ModelType { get; set; } = typeof(Guid);
public override Task ExecuteAsync()
{
throw new NotImplementedException();
}
public Type GetModelType() => ModelType;
}
private abstract class NoModelPropertyBase<TModel> : RazorPage
{
[RazorInject]

View File

@ -1747,6 +1747,49 @@ namespace Microsoft.AspNetCore.Mvc.Razor
Assert.Equal(expected, viewContext.Writer.ToString());
}
[Fact]
public async Task RenderAsync_InvokesOnAfterPageActivated()
{
// Arrange
var viewStart = new TestableRazorPage(_ => { });
var page = new TestableRazorPage(p => { p.Layout = LayoutPath; });
var layout = new TestableRazorPage(p => { p.RenderBodyPublic(); });
var expected = new HashSet<IRazorPage>();
var onAfterPageActivatedCalled = 0;
var activated = new HashSet<IRazorPage>();
var pageActivator = new Mock<IRazorPageActivator>();
pageActivator.Setup(p => p.Activate(It.IsAny<IRazorPage>(), It.IsAny<ViewContext>()))
.Callback((IRazorPage p, ViewContext v) => activated.Add(p));
var viewEngine = new Mock<IRazorViewEngine>();
viewEngine.Setup(v => v.FindPage(It.IsAny<ActionContext>(), LayoutPath))
.Returns(new RazorPageResult(LayoutPath, layout));
var view = new RazorView(
viewEngine.Object,
pageActivator.Object,
new[] { viewStart },
page,
new HtmlTestEncoder(),
new DiagnosticListener("Microsoft.AspNetCore.Mvc.Razor"))
{
OnAfterPageActivated = AssertActivated,
};
var viewContext = CreateViewContext(view);
// Act
await view.RenderAsync(viewContext);
Assert.Equal(3, onAfterPageActivatedCalled);
void AssertActivated(IRazorPage p, ViewContext v)
{
onAfterPageActivatedCalled++;
expected.Add(p);
Assert.Equal(expected, activated);
}
}
private static ViewContext CreateViewContext(RazorView view)
{
var httpContext = new DefaultHttpContext();

View File

@ -1,7 +1,7 @@
// 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.ViewFeatures.Test;
using Resources = Microsoft.AspNetCore.Mvc.ViewFeatures.Test.Resources;
namespace Microsoft.AspNetCore.Mvc
{

View File

@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesWebSite.ViewDataSetInViewStart
{
public class Index : PageModel
{
[ViewData]
public string ValueFromPageModel => "Value from Page Model";
}
}

View File

@ -0,0 +1,7 @@
@page
@namespace RazorPagesWebSite.ViewDataSetInViewStart
@model Index
@{
ViewData["ValueFromPage"] = "Value from Page";
}
Sample that shows ViewData attributes being set in a PageModel.

View File

@ -0,0 +1,4 @@
@RenderBody()
<span id="valuefromviewstart">@ViewData["ValueFromViewStart"]</span>
<span id="valuefrompage">@ViewData["ValueFromPage"]</span>
<span id="valuefrompagemodel">@ViewData["ValueFromPageModel"]</span>

View File

@ -0,0 +1,4 @@
@{
Layout = "_Layout";
ViewData["ValueFromViewStart"] = "Value from _ViewStart";
}

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 VersioningWebSite
{
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

@ -24,21 +24,5 @@ namespace VersioningWebSite
{
app.UseMvcWithDefaultRoute();
}
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,37 @@
// 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.Hosting;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
namespace VersioningWebSite
{
public class StartupWithDispatching
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDispatcher();
// Add MVC services to the services container
services.AddMvc();
services.AddScoped<TestResponseGenerator>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}
public void Configure(IApplicationBuilder app)
{
app.UseDispatcher();
app.UseMvcWithEndpoint(endpoints =>
{
endpoints.MapEndpoint(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}

View File

@ -3,10 +3,11 @@
using System;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
namespace VersioningWebSite
{
public class VersionAttribute : Attribute, IActionConstraintFactory
public class VersionAttribute : Attribute, IActionConstraintFactory, IEndpointConstraintFactory
{
private int? _maxVersion;
private int? _minVersion;
@ -32,7 +33,12 @@ namespace VersioningWebSite
public bool IsReusable => true;
public IActionConstraint CreateInstance(IServiceProvider services)
IActionConstraint IActionConstraintFactory.CreateInstance(IServiceProvider services)
{
return new VersionRangeValidator(_minVersion, _maxVersion) { Order = _order ?? 0 };
}
IEndpointConstraint IEndpointConstraintFactory.CreateInstance(IServiceProvider services)
{
return new VersionRangeValidator(_minVersion, _maxVersion) { Order = _order ?? 0 };
}

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc.Routing;
namespace VersioningWebSite
{
public class VersionDeleteAttribute : VersionRoute, IActionHttpMethodProvider
public class VersionDeleteAttribute : VersionRouteAttribute, IActionHttpMethodProvider
{
public VersionDeleteAttribute(string template)
: base(template)

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc.Routing;
namespace VersioningWebSite
{
public class VersionGetAttribute : VersionRoute, IActionHttpMethodProvider
public class VersionGetAttribute : VersionRouteAttribute, IActionHttpMethodProvider
{
public VersionGetAttribute(string template)
: base(template)

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc.Routing;
namespace VersioningWebSite
{
public class VersionPostAttribute : VersionRoute, IActionHttpMethodProvider
public class VersionPostAttribute : VersionRouteAttribute, IActionHttpMethodProvider
{
public VersionPostAttribute(string template)
: base(template)

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc.Routing;
namespace VersioningWebSite
{
public class VersionPutAttribute : VersionRoute, IActionHttpMethodProvider
public class VersionPutAttribute : VersionRouteAttribute, IActionHttpMethodProvider
{
public VersionPutAttribute(string template)
: base(template)

View File

@ -3,10 +3,11 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
namespace VersioningWebSite
{
public class VersionRangeValidator : IActionConstraint
public class VersionRangeValidator : IActionConstraint, IEndpointConstraint
{
private readonly int? _minVersion;
private readonly int? _maxVersion;
@ -25,9 +26,19 @@ namespace VersioningWebSite
}
public bool Accept(ActionConstraintContext context)
{
return ProcessRequest(context.RouteContext.HttpContext.Request);
}
public bool Accept(EndpointConstraintContext context)
{
return ProcessRequest(context.HttpContext.Request);
}
private bool ProcessRequest(HttpRequest request)
{
int version;
if (int.TryParse(GetVersion(context.RouteContext.HttpContext.Request), out version))
if (int.TryParse(GetVersion(request), out version))
{
return (_minVersion == null || _minVersion <= version) &&
(_maxVersion == null || _maxVersion >= version);

View File

@ -5,12 +5,13 @@ using System;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
namespace VersioningWebSite
{
public class VersionRoute : RouteAttribute, IActionConstraintFactory
public class VersionRouteAttribute : RouteAttribute, IActionConstraintFactory, IEndpointConstraintFactory
{
private readonly IActionConstraint _constraint;
private readonly IActionConstraint _actionConstraint;
// 5
// [5]
@ -28,12 +29,12 @@ namespace VersioningWebSite
public bool IsReusable => true;
public VersionRoute(string template)
public VersionRouteAttribute(string template)
: base(template)
{
}
public VersionRoute(string template, string versionRange)
public VersionRouteAttribute(string template, string versionRange)
: base(template)
{
var constraint = CreateVersionConstraint(versionRange);
@ -44,7 +45,7 @@ namespace VersioningWebSite
throw new ArgumentException(message, "versionRange");
}
_constraint = constraint;
_actionConstraint = constraint;
}
private static IActionConstraint CreateVersionConstraint(string versionRange)
@ -122,9 +123,14 @@ namespace VersioningWebSite
}
}
public IActionConstraint CreateInstance(IServiceProvider services)
IActionConstraint IActionConstraintFactory.CreateInstance(IServiceProvider services)
{
return _constraint;
return _actionConstraint;
}
IEndpointConstraint IEndpointConstraintFactory.CreateInstance(IServiceProvider services)
{
return (IEndpointConstraint)_actionConstraint;
}
}
}