Merge remote-tracking branch 'origin/release/2.1' into dev

This commit is contained in:
Pranav K 2018-03-21 15:41:22 -07:00
commit 3141179344
No known key found for this signature in database
GPG Key ID: 1963DA6D96C3057A
37 changed files with 1674 additions and 1407 deletions

View File

@ -4,83 +4,84 @@
</PropertyGroup>
<PropertyGroup Label="Package Versions">
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview2-15739</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview2-30328</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview3-15746</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview3-30392</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftAspNetWebApiClientPackageVersion>5.2.4</MicrosoftAspNetWebApiClientPackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>2.6.1</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.6.1</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.1.0-preview2-30328</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.1.0-preview2-26308-02</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.1.0-preview2-30328</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.1.0-preview3-30392</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.1.0-preview2-26313-01</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.1.0-preview3-30392</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26308-01</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30328</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.0</MicrosoftNETTestSdkPackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26314-02</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview3-30392</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>2.1.0-preview3-30392</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>
<NewtonsoftJsonBsonPackageVersion>1.0.1</NewtonsoftJsonBsonPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>4.5.0-preview2-26308-02</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0-preview2-26308-02</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview2-26308-02</SystemThreadingTasksExtensionsPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>4.5.0-preview2-26313-01</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0-preview2-26313-01</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview2-26313-01</SystemThreadingTasksExtensionsPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>

View File

@ -1,2 +1,2 @@
version:2.1.0-preview2-15741
commithash:d944172721e77b6ca05a512303a0859634786746
version:2.1.0-preview3-15746
commithash:bd7208b1b1533dad0fac5440948312ff269f0fb9

View File

@ -22,6 +22,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsConfigurationJsonPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
<PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftNETSdkRazorPackageVersion)" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@ -1,25 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
/// <summary>
/// An <see cref="AssemblyPart"/> that was added by an assembly that referenced it through the use
/// of an assembly metadata attribute.
/// </summary>
public class AdditionalAssemblyPart : AssemblyPart, ICompilationReferencesProvider, IApplicationPartTypeProvider
{
/// <inheritdoc />
public AdditionalAssemblyPart(Assembly assembly) : base(assembly)
{
}
IEnumerable<string> ICompilationReferencesProvider.GetReferencePaths() => Array.Empty<string>();
IEnumerable<TypeInfo> IApplicationPartTypeProvider.Types => Array.Empty<TypeInfo>();
}
}

View File

@ -0,0 +1,283 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.Extensions.DependencyModel;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
internal class ApplicationAssembliesProvider
{
internal static HashSet<string> ReferenceAssemblies { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"Microsoft.AspNetCore.Mvc",
"Microsoft.AspNetCore.Mvc.Abstractions",
"Microsoft.AspNetCore.Mvc.ApiExplorer",
"Microsoft.AspNetCore.Mvc.Core",
"Microsoft.AspNetCore.Mvc.Cors",
"Microsoft.AspNetCore.Mvc.DataAnnotations",
"Microsoft.AspNetCore.Mvc.Formatters.Json",
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
"Microsoft.AspNetCore.Mvc.Localization",
"Microsoft.AspNetCore.Mvc.Razor",
"Microsoft.AspNetCore.Mvc.Razor.Extensions",
"Microsoft.AspNetCore.Mvc.RazorPages",
"Microsoft.AspNetCore.Mvc.TagHelpers",
"Microsoft.AspNetCore.Mvc.ViewFeatures",
};
/// <summary>
/// Returns an ordered list of application assemblies.
/// <para>
/// The order is as follows:
/// * Entry assembly
/// * Assemblies specified in the application's deps file ordered by name.
/// <para>
/// Each assembly is immediately followed by assemblies specified by annotated <see cref="RelatedAssemblyAttribute"/> ordered by name.
/// </para>
/// </para>
/// </summary>
public IEnumerable<Assembly> ResolveAssemblies(Assembly entryAssembly)
{
var dependencyContext = LoadDependencyContext(entryAssembly);
IEnumerable<AssemblyItem> assemblyItems;
if (dependencyContext == null)
{
assemblyItems = new[] { GetAssemblyItem(entryAssembly) };
}
else
{
assemblyItems = ResolveFromDependencyContext(dependencyContext);
}
assemblyItems = assemblyItems
.OrderBy(item => item.Assembly == entryAssembly ? 0 : 1)
.ThenBy(item => item.Assembly.FullName, StringComparer.Ordinal);
foreach (var item in assemblyItems)
{
yield return item.Assembly;
foreach (var associatedAssembly in item.RelatedAssemblies.Distinct().OrderBy(assembly => assembly.FullName, StringComparer.Ordinal))
{
yield return associatedAssembly;
}
}
}
protected virtual DependencyContext LoadDependencyContext(Assembly assembly) => DependencyContext.Load(assembly);
private List<AssemblyItem> ResolveFromDependencyContext(DependencyContext dependencyContext)
{
var assemblyItems = new List<AssemblyItem>();
var relatedAssemblies = new Dictionary<Assembly, AssemblyItem>();
var candidateAssemblies = GetCandidateLibraries(dependencyContext)
.SelectMany(library => GetLibraryAssemblies(dependencyContext, library));
foreach (var assembly in candidateAssemblies)
{
var assemblyItem = GetAssemblyItem(assembly);
assemblyItems.Add(assemblyItem);
foreach (var relatedAssembly in assemblyItem.RelatedAssemblies)
{
if (relatedAssemblies.TryGetValue(relatedAssembly, out var otherEntry))
{
var message = string.Join(
Environment.NewLine,
Resources.FormatApplicationAssembliesProvider_DuplicateRelatedAssembly(relatedAssembly.FullName),
otherEntry.Assembly.FullName,
assembly.FullName);
throw new InvalidOperationException(message);
}
relatedAssemblies.Add(relatedAssembly, assemblyItem);
}
}
// Remove any top level assemblies that appear as an associated assembly.
assemblyItems.RemoveAll(item => relatedAssemblies.ContainsKey(item.Assembly));
return assemblyItems;
}
protected virtual IEnumerable<Assembly> GetLibraryAssemblies(DependencyContext dependencyContext, RuntimeLibrary runtimeLibrary)
{
foreach (var assemblyName in runtimeLibrary.GetDefaultAssemblyNames(dependencyContext))
{
var assembly = Assembly.Load(assemblyName);
yield return assembly;
}
}
protected virtual IReadOnlyList<Assembly> GetRelatedAssemblies(Assembly assembly)
{
// Do not require related assemblies to be available in the default code path.
return RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: false);
}
private AssemblyItem GetAssemblyItem(Assembly assembly)
{
var relatedAssemblies = GetRelatedAssemblies(assembly);
// Ensure we don't have any cycles. A cycle could be formed if a related assembly points to the primary assembly.
foreach (var relatedAssembly in relatedAssemblies)
{
if (relatedAssembly.IsDefined(typeof(RelatedAssemblyAttribute)))
{
throw new InvalidOperationException(
Resources.FormatApplicationAssembliesProvider_RelatedAssemblyCannotDefineAdditional(relatedAssembly.FullName, assembly.FullName));
}
}
return new AssemblyItem(assembly, relatedAssemblies);
}
// Returns a list of libraries that references the assemblies in <see cref="ReferenceAssemblies"/>.
// By default it returns all assemblies that reference any of the primary MVC assemblies
// while ignoring MVC assemblies.
// Internal for unit testing
internal static IEnumerable<RuntimeLibrary> GetCandidateLibraries(DependencyContext dependencyContext)
{
var candidatesResolver = new CandidateResolver(dependencyContext.RuntimeLibraries, ReferenceAssemblies);
return candidatesResolver.GetCandidates();
}
private class CandidateResolver
{
private readonly IDictionary<string, Dependency> _runtimeDependencies;
public CandidateResolver(IReadOnlyList<RuntimeLibrary> runtimeDependencies, ISet<string> referenceAssemblies)
{
var dependenciesWithNoDuplicates = new Dictionary<string, Dependency>(StringComparer.OrdinalIgnoreCase);
foreach (var dependency in runtimeDependencies)
{
if (dependenciesWithNoDuplicates.ContainsKey(dependency.Name))
{
throw new InvalidOperationException(Resources.FormatCandidateResolver_DifferentCasedReference(dependency.Name));
}
dependenciesWithNoDuplicates.Add(dependency.Name, CreateDependency(dependency, referenceAssemblies));
}
_runtimeDependencies = dependenciesWithNoDuplicates;
}
private Dependency CreateDependency(RuntimeLibrary library, ISet<string> referenceAssemblies)
{
var classification = DependencyClassification.Unknown;
if (referenceAssemblies.Contains(library.Name))
{
classification = DependencyClassification.MvcReference;
}
return new Dependency(library, classification);
}
private DependencyClassification ComputeClassification(string dependency)
{
if (!_runtimeDependencies.ContainsKey(dependency))
{
// Library does not have runtime dependency. Since we can't infer
// anything about it's references, we'll assume it does not have a reference to Mvc.
return DependencyClassification.DoesNotReferenceMvc;
}
var candidateEntry = _runtimeDependencies[dependency];
if (candidateEntry.Classification != DependencyClassification.Unknown)
{
return candidateEntry.Classification;
}
else
{
var classification = DependencyClassification.DoesNotReferenceMvc;
foreach (var candidateDependency in candidateEntry.Library.Dependencies)
{
var dependencyClassification = ComputeClassification(candidateDependency.Name);
if (dependencyClassification == DependencyClassification.ReferencesMvc ||
dependencyClassification == DependencyClassification.MvcReference)
{
classification = DependencyClassification.ReferencesMvc;
break;
}
}
candidateEntry.Classification = classification;
return classification;
}
}
public IEnumerable<RuntimeLibrary> GetCandidates()
{
foreach (var dependency in _runtimeDependencies)
{
if (ComputeClassification(dependency.Key) == DependencyClassification.ReferencesMvc)
{
yield return dependency.Value.Library;
}
}
}
private class Dependency
{
public Dependency(RuntimeLibrary library, DependencyClassification classification)
{
Library = library;
Classification = classification;
}
public RuntimeLibrary Library { get; }
public DependencyClassification Classification { get; set; }
public override string ToString()
{
return $"Library: {Library.Name}, Classification: {Classification}";
}
}
private enum DependencyClassification
{
Unknown = 0,
/// <summary>
/// References (directly or transitively) one of the Mvc packages listed in
/// <see cref="ReferenceAssemblies"/>.
/// </summary>
ReferencesMvc = 1,
/// <summary>
/// Does not reference (directly or transitively) one of the Mvc packages listed by
/// <see cref="ReferenceAssemblies"/>.
/// </summary>
DoesNotReferenceMvc = 2,
/// <summary>
/// One of the references listed in <see cref="ReferenceAssemblies"/>.
/// </summary>
MvcReference = 3,
}
}
private readonly struct AssemblyItem
{
public AssemblyItem(Assembly assembly, IReadOnlyList<Assembly> associatedAssemblies)
{
Assembly = assembly;
RelatedAssemblies = associatedAssemblies;
}
public Assembly Assembly { get; }
public IReadOnlyList<Assembly> RelatedAssemblies { get; }
}
}
}

View File

@ -1,8 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Core;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
@ -19,6 +21,11 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
public static readonly string DefaultContextName = "Default";
/// <summary>
/// Default implementation for <see cref="ApplicationPartFactory"/>.
/// </summary>
public static ApplicationPartFactory Default { get; } = new DefaultApplicationPartFactory();
/// <summary>
/// Gets one or more <see cref="ApplicationPart"/> instances for the specified <paramref name="assembly"/>.
/// </summary>
@ -27,5 +34,52 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
/// The context name. By default, value of this parameter is <see cref="DefaultContextName"/>.
/// </param>
public abstract IEnumerable<ApplicationPart> GetApplicationParts(Assembly assembly, string context);
/// <summary>
/// Gets the <see cref="ApplicationPartFactory"/> for the specified assembly.
/// <para>
/// An assembly may specify an <see cref="ApplicationPartFactory"/> using <see cref="ProvideApplicationPartFactoryAttribute"/>.
/// Otherwise, <see cref="ApplicationPartFactory.Default"/> is used.
/// </para>
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/>.</param>
/// <returns>An instance of <see cref="ApplicationPartFactory"/>.</returns>
public static ApplicationPartFactory GetApplicationPartFactory(Assembly assembly)
{
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
var provideAttribute = assembly.GetCustomAttribute<ProvideApplicationPartFactoryAttribute>();
if (provideAttribute == null)
{
return ApplicationPartFactory.Default;
}
var type = provideAttribute.GetFactoryType();
if (!typeof(ApplicationPartFactory).IsAssignableFrom(type))
{
throw new InvalidOperationException(Resources.FormatApplicationPartFactory_InvalidFactoryType(
type,
nameof(ProvideApplicationPartFactoryAttribute),
typeof(ApplicationPartFactory)));
}
return (ApplicationPartFactory)Activator.CreateInstance(type);
}
private class DefaultApplicationPartFactory : ApplicationPartFactory
{
public override IEnumerable<ApplicationPart> GetApplicationParts(Assembly assembly, string context)
{
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
yield return new AssemblyPart(assembly);
}
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
@ -48,5 +49,21 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
provider.PopulateFeature(ApplicationParts, feature);
}
}
internal void PopulateDefaultParts(string entryAssemblyName)
{
var entryAssembly = Assembly.Load(new AssemblyName(entryAssemblyName));
var assembliesProvider = new ApplicationAssembliesProvider();
var applicationAssemblies = assembliesProvider.ResolveAssemblies(entryAssembly);
foreach (var assembly in applicationAssemblies)
{
var partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
foreach (var part in partFactory.GetApplicationParts(assembly, context: ApplicationPartFactory.DefaultContextName))
{
ApplicationParts.Add(part);
}
}
}
}
}

View File

@ -0,0 +1,24 @@
// 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.Reflection;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
/// <summary>
/// An <see cref="ApplicationPartFactory"/> that produces no parts.
/// <para>
/// This factory may be used to to preempt Mvc's default part discovery allowing for custom configuration at a later stage.
/// </para>
/// </summary>
public class NullApplicationPartFactory : ApplicationPartFactory
{
/// <inheritdoc />
public override IEnumerable<ApplicationPart> GetApplicationParts(Assembly assembly, string context)
{
return Enumerable.Empty<ApplicationPart>();
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Mvc.Core;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
@ -11,15 +12,40 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public sealed class ProvideApplicationPartFactoryAttribute : Attribute
{
private readonly Type _applicationPartFactoryType;
private readonly string _applicationPartFactoryTypeName;
/// <summary>
/// Creates a new instance of <see cref="ProvideApplicationPartFactoryAttribute"/> with the specified type.
/// </summary>
/// <param name="factoryType">The factory type.</param>
public ProvideApplicationPartFactoryAttribute(Type factoryType)
{
ApplicationPartFactoryType = factoryType ?? throw new ArgumentNullException(nameof(factoryType));
_applicationPartFactoryType = factoryType ?? throw new ArgumentNullException(nameof(factoryType));
}
/// <summary>
/// Creates a new instance of <see cref="ProvideApplicationPartFactoryAttribute"/> with the specified type name.
/// </summary>
/// <param name="factoryTypeName">The assembly qualified type name.</param>
public ProvideApplicationPartFactoryAttribute(string factoryTypeName)
{
if (string.IsNullOrEmpty(factoryTypeName))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(factoryTypeName));
}
_applicationPartFactoryTypeName = factoryTypeName;
}
public Type ApplicationPartFactoryType { get; }
/// <summary>
/// Gets the factory type.
/// </summary>
/// <returns></returns>
public Type GetFactoryType()
{
return _applicationPartFactoryType ??
Type.GetType(_applicationPartFactoryTypeName, throwOnError: true);
}
}
}

View File

@ -2,23 +2,110 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Core;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
/// <summary>
/// Specifies a assembly to load as part of MVC's assembly discovery mechanism.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class RelatedAssemblyAttribute : Attribute
{
public RelatedAssemblyAttribute(string name)
private static readonly Func<string, Assembly> AssemblyLoadFileDelegate = Assembly.LoadFile;
/// <summary>
/// Initializes a new instance of <see cref="RelatedAssemblyAttribute"/>.
/// </summary>
/// <param name="assemblyFileName">The file name, without extension, of the related assembly.</param>
public RelatedAssemblyAttribute(string assemblyFileName)
{
if (string.IsNullOrEmpty(name))
if (string.IsNullOrEmpty(assemblyFileName))
{
// Temporary workaround until we have a new build of RazorSdk.
// TODO: Uncomment the below line.
// throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(name));
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(assemblyFileName));
}
AssemblyFileName = assemblyFileName;
}
public string Name { get; }
/// <summary>
/// Gets the assembly file name without extension.
/// </summary>
public string AssemblyFileName { get; }
/// <summary>
/// Gets <see cref="Assembly"/> instances specified by <see cref="RelatedAssemblyAttribute"/>.
/// </summary>
/// <param name="assembly">The assembly containing <see cref="RelatedAssemblyAttribute"/> instances.</param>
/// <param name="throwOnError">Determines if the method throws if a related assembly could not be located.</param>
/// <returns>Related <see cref="Assembly"/> instances.</returns>
public static IReadOnlyList<Assembly> GetRelatedAssemblies(Assembly assembly, bool throwOnError)
{
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
return GetRelatedAssemblies(assembly, throwOnError, AssemblyLoadFileDelegate);
}
internal static IReadOnlyList<Assembly> GetRelatedAssemblies(Assembly assembly, bool throwOnError, Func<string, Assembly> loadFile)
{
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
// MVC will specifically look for related parts in the same physical directory as the assembly.
// No-op if the assembly does not have a location.
if (assembly.IsDynamic || string.IsNullOrEmpty(assembly.CodeBase))
{
return Array.Empty<Assembly>();
}
var attributes = assembly.GetCustomAttributes<RelatedAssemblyAttribute>().ToArray();
if (attributes.Length == 0)
{
return Array.Empty<Assembly>();
}
var assemblyName = assembly.GetName().Name;
var assemblyDirectory = Path.GetDirectoryName(assembly.CodeBase);
var relatedAssemblies = new List<Assembly>();
for (var i = 0; i < attributes.Length; i++)
{
var attribute = attributes[i];
if (string.Equals(assemblyName, attribute.AssemblyFileName, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
Resources.FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf(nameof(RelatedAssemblyAttribute), assemblyName));
}
var relatedAssemblyLocation = Path.Combine(assemblyDirectory, attribute.AssemblyFileName + ".dll");
if (!File.Exists(relatedAssemblyLocation))
{
if (throwOnError)
{
throw new FileNotFoundException(
Resources.FormatRelatedAssemblyAttribute_CouldNotBeFound(attribute.AssemblyFileName, assemblyName, assemblyDirectory),
relatedAssemblyLocation);
}
else
{
continue;
}
}
var relatedAssembly = loadFile(relatedAssemblyLocation);
relatedAssemblies.Add(relatedAssembly);
}
return relatedAssemblies;
}
}
}

View File

@ -87,11 +87,7 @@ namespace Microsoft.Extensions.DependencyInjection
return manager;
}
var parts = DefaultAssemblyPartDiscoveryProvider.DiscoverAssemblyParts(entryAssemblyName);
foreach (var part in parts)
{
manager.ApplicationParts.Add(part);
}
manager.PopulateDefaultParts(entryAssemblyName);
}
return manager;

View File

@ -1,406 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.Extensions.DependencyModel;
namespace Microsoft.AspNetCore.Mvc.Internal
{
// Discovers assemblies that are part of the MVC application using the DependencyContext.
public static class DefaultAssemblyPartDiscoveryProvider
{
private static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews";
private static readonly IReadOnlyList<string> ViewAssemblySuffixes = new string[]
{
PrecompiledViewsAssemblySuffix,
".Views",
};
private const string AdditionalReferenceKey = "Microsoft.AspNetCore.Mvc.AdditionalReference";
private static readonly char[] MetadataSeparators = new[] { ',' };
internal static HashSet<string> ReferenceAssemblies { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"Microsoft.AspNetCore.All",
"Microsoft.AspNetCore.Mvc",
"Microsoft.AspNetCore.Mvc.Abstractions",
"Microsoft.AspNetCore.Mvc.ApiExplorer",
"Microsoft.AspNetCore.Mvc.Core",
"Microsoft.AspNetCore.Mvc.Cors",
"Microsoft.AspNetCore.Mvc.DataAnnotations",
"Microsoft.AspNetCore.Mvc.Formatters.Json",
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
"Microsoft.AspNetCore.Mvc.Localization",
"Microsoft.AspNetCore.Mvc.Razor",
"Microsoft.AspNetCore.Mvc.Razor.Extensions",
"Microsoft.AspNetCore.Mvc.RazorPages",
"Microsoft.AspNetCore.Mvc.TagHelpers",
"Microsoft.AspNetCore.Mvc.ViewFeatures"
};
// For testing purposes only.
internal static Func<string, Assembly> AssemblyLoader { get; set; } = Assembly.LoadFile;
internal static Func<string, bool> AssemblyResolver { get; set; } = File.Exists;
public static IEnumerable<ApplicationPart> DiscoverAssemblyParts(string entryPointAssemblyName)
{
// We need to produce a stable order of the parts that is given by:
// 1) Parts that are not additional parts go before parts that are additional parts.
// 2) The entry point part goes before any other part in the system.
// 3) The entry point additional parts go before any other additional parts.
// 4) Parts are finally ordered by their full name to produce a stable ordering.
var entryAssembly = Assembly.Load(new AssemblyName(entryPointAssemblyName));
var context = DependencyContext.Load(entryAssembly);
var candidateAssemblies = new SortedSet<Assembly>(
GetCandidateAssemblies(entryAssembly, context),
FullNameAssemblyComparer.Instance);
var (additionalReferences, entryAssemblyAdditionalReferences) = ResolveAdditionalReferences(
entryAssembly,
candidateAssemblies);
candidateAssemblies.Remove(entryAssembly);
candidateAssemblies.ExceptWith(additionalReferences);
candidateAssemblies.ExceptWith(entryAssemblyAdditionalReferences);
// Create the list of assembly parts.
return CreateParts();
IEnumerable<AssemblyPart> CreateParts()
{
yield return new AssemblyPart(entryAssembly);
foreach (var candidateAssembly in candidateAssemblies)
{
yield return new AssemblyPart(candidateAssembly);
}
foreach (var entryAdditionalAssembly in entryAssemblyAdditionalReferences)
{
yield return new AdditionalAssemblyPart(entryAdditionalAssembly);
}
foreach (var additionalAssembly in additionalReferences)
{
yield return new AdditionalAssemblyPart(additionalAssembly);
}
}
}
internal static AdditionalReferencesPair ResolveAdditionalReferences(
Assembly entryAssembly,
SortedSet<Assembly> candidateAssemblies)
{
var additionalAssemblyReferences = candidateAssemblies
.Select(ca =>
(assembly: ca,
metadata: ca.GetCustomAttributes<AssemblyMetadataAttribute>()
.Where(ama => ama.Key.Equals(AdditionalReferenceKey, StringComparison.Ordinal)).ToArray()));
// Find out all the additional references defined by the assembly.
// [assembly: AssemblyMetadataAttribute("Microsoft.AspNetCore.Mvc.AdditionalReference", "Library.PrecompiledViews.dll,true|false")]
var additionalReferences = new SortedSet<Assembly>(FullNameAssemblyComparer.Instance);
var entryAssemblyAdditionalReferences = new SortedSet<Assembly>(FullNameAssemblyComparer.Instance);
foreach (var (assembly, metadata) in additionalAssemblyReferences)
{
if (metadata.Length > 0)
{
foreach (var metadataAttribute in metadata)
{
AddAdditionalReference(
LoadFromMetadata(assembly, metadataAttribute),
entryAssembly,
assembly,
additionalReferences,
entryAssemblyAdditionalReferences);
}
}
else
{
// Fallback to loading the views like in previous versions if the additional reference metadata
// attribute is not present.
AddAdditionalReference(
LoadFromConvention(assembly),
entryAssembly,
assembly,
additionalReferences,
entryAssemblyAdditionalReferences);
}
}
return new AdditionalReferencesPair
{
AdditionalAssemblies = additionalReferences,
EntryAssemblyAdditionalAssemblies = entryAssemblyAdditionalReferences
};
}
private static Assembly LoadFromMetadata(Assembly assembly, AssemblyMetadataAttribute metadataAttribute)
{
var (metadataPath, metadataIncludeByDefault) = ParseMetadataAttribute(metadataAttribute);
if (metadataPath == null ||
metadataIncludeByDefault == null ||
!string.Equals(metadataIncludeByDefault, "true", StringComparison.OrdinalIgnoreCase))
{
return null;
}
var fileName = Path.GetFileName(metadataPath);
var filePath = Path.Combine(Path.GetDirectoryName(assembly.Location), fileName);
var additionalAssembly = LoadAssembly(filePath);
if (additionalAssembly == null)
{
return null;
}
return additionalAssembly;
}
private static (string metadataPath, string metadataIncludeByDefault) ParseMetadataAttribute(
AssemblyMetadataAttribute metadataAttribute)
{
var data = metadataAttribute.Value.Split(MetadataSeparators);
if (data.Length != 2 || string.IsNullOrWhiteSpace(data[0]) || string.IsNullOrWhiteSpace(data[1]))
{
return default;
}
return (data[0], data[1]);
}
private static Assembly LoadAssembly(string filePath)
{
Assembly viewsAssembly = null;
if (AssemblyResolver(filePath))
{
try
{
viewsAssembly = AssemblyLoader(filePath);
}
catch (FileLoadException)
{
// Don't throw if assembly cannot be loaded. This can happen if the file is not a managed assembly.
}
}
return viewsAssembly;
}
private static Assembly LoadFromConvention(Assembly assembly)
{
if (assembly.IsDynamic || string.IsNullOrEmpty(assembly.Location))
{
return null;
}
for (var i = 0; i < ViewAssemblySuffixes.Count; i++)
{
var fileName = assembly.GetName().Name + ViewAssemblySuffixes[i] + ".dll";
var filePath = Path.Combine(Path.GetDirectoryName(assembly.Location), fileName);
var viewsAssembly = LoadAssembly(filePath);
if (viewsAssembly != null)
{
return viewsAssembly;
}
}
return null;
}
private static void AddAdditionalReference(
Assembly additionalReference,
Assembly entryAssembly,
Assembly assembly,
SortedSet<Assembly> additionalReferences,
SortedSet<Assembly> entryAssemblyAdditionalReferences)
{
if (additionalReference == null ||
additionalReferences.Contains(additionalReference) ||
entryAssemblyAdditionalReferences.Contains(additionalReference))
{
return;
}
if (assembly.Equals(entryAssembly))
{
entryAssemblyAdditionalReferences.Add(additionalReference);
}
else
{
additionalReferences.Add(additionalReference);
}
}
internal class AdditionalReferencesPair
{
public SortedSet<Assembly> AdditionalAssemblies { get; set; }
public SortedSet<Assembly> EntryAssemblyAdditionalAssemblies { get; set; }
public void Deconstruct(
out SortedSet<Assembly> additionalAssemblies,
out SortedSet<Assembly> entryAssemblyAdditionalAssemblies)
{
additionalAssemblies = AdditionalAssemblies;
entryAssemblyAdditionalAssemblies = EntryAssemblyAdditionalAssemblies;
}
}
internal class FullNameAssemblyComparer : IComparer<Assembly>
{
public static IComparer<Assembly> Instance { get; } = new FullNameAssemblyComparer();
public int Compare(Assembly x, Assembly y) =>
string.Compare(x?.FullName, y?.FullName, StringComparison.Ordinal);
}
internal static IEnumerable<Assembly> GetCandidateAssemblies(Assembly entryAssembly, DependencyContext dependencyContext)
{
if (dependencyContext == null)
{
// Use the entry assembly as the sole candidate.
return new[] { entryAssembly };
}
return GetCandidateLibraries(dependencyContext)
.SelectMany(library => library.GetDefaultAssemblyNames(dependencyContext))
.Select(Assembly.Load);
}
// Returns a list of libraries that references the assemblies in <see cref="ReferenceAssemblies"/>.
// By default it returns all assemblies that reference any of the primary MVC assemblies
// while ignoring MVC assemblies.
// Internal for unit testing
internal static IEnumerable<RuntimeLibrary> GetCandidateLibraries(DependencyContext dependencyContext)
{
if (ReferenceAssemblies == null)
{
return Enumerable.Empty<RuntimeLibrary>();
}
var candidatesResolver = new CandidateResolver(dependencyContext.RuntimeLibraries, ReferenceAssemblies);
return candidatesResolver.GetCandidates();
}
private class CandidateResolver
{
private readonly IDictionary<string, Dependency> _runtimeDependencies;
public CandidateResolver(IReadOnlyList<RuntimeLibrary> runtimeDependencies, ISet<string> referenceAssemblies)
{
var dependenciesWithNoDuplicates = new Dictionary<string, Dependency>(StringComparer.OrdinalIgnoreCase);
foreach (var dependency in runtimeDependencies)
{
if (dependenciesWithNoDuplicates.ContainsKey(dependency.Name))
{
throw new InvalidOperationException(Resources.FormatCandidateResolver_DifferentCasedReference(dependency.Name));
}
dependenciesWithNoDuplicates.Add(dependency.Name, CreateDependency(dependency, referenceAssemblies));
}
_runtimeDependencies = dependenciesWithNoDuplicates;
}
private Dependency CreateDependency(RuntimeLibrary library, ISet<string> referenceAssemblies)
{
var classification = DependencyClassification.Unknown;
if (referenceAssemblies.Contains(library.Name))
{
classification = DependencyClassification.MvcReference;
}
return new Dependency(library, classification);
}
private DependencyClassification ComputeClassification(string dependency)
{
if (!_runtimeDependencies.ContainsKey(dependency))
{
// Library does not have runtime dependency. Since we can't infer
// anything about it's references, we'll assume it does not have a reference to Mvc.
return DependencyClassification.DoesNotReferenceMvc;
}
var candidateEntry = _runtimeDependencies[dependency];
if (candidateEntry.Classification != DependencyClassification.Unknown)
{
return candidateEntry.Classification;
}
else
{
var classification = DependencyClassification.DoesNotReferenceMvc;
foreach (var candidateDependency in candidateEntry.Library.Dependencies)
{
var dependencyClassification = ComputeClassification(candidateDependency.Name);
if (dependencyClassification == DependencyClassification.ReferencesMvc ||
dependencyClassification == DependencyClassification.MvcReference)
{
classification = DependencyClassification.ReferencesMvc;
break;
}
}
candidateEntry.Classification = classification;
return classification;
}
}
public IEnumerable<RuntimeLibrary> GetCandidates()
{
foreach (var dependency in _runtimeDependencies)
{
if (ComputeClassification(dependency.Key) == DependencyClassification.ReferencesMvc)
{
yield return dependency.Value.Library;
}
}
}
private class Dependency
{
public Dependency(RuntimeLibrary library, DependencyClassification classification)
{
Library = library;
Classification = classification;
}
public RuntimeLibrary Library { get; }
public DependencyClassification Classification { get; set; }
public override string ToString()
{
return $"Library: {Library.Name}, Classification: {Classification}";
}
}
private enum DependencyClassification
{
Unknown = 0,
/// <summary>
/// References (directly or transitively) one of the Mvc packages listed in
/// <see cref="ReferenceAssemblies"/>.
/// </summary>
ReferencesMvc = 1,
/// <summary>
/// Does not reference (directly or transitively) one of the Mvc packages listed by
/// <see cref="ReferenceAssemblies"/>.
/// </summary>
DoesNotReferenceMvc = 2,
/// <summary>
/// One of the references listed in <see cref="ReferenceAssemblies"/>.
/// </summary>
MvcReference = 3,
}
}
}
}

View File

@ -1368,6 +1368,76 @@ namespace Microsoft.AspNetCore.Mvc.Core
internal static string FormatVirtualFileResultExecutor_NoFileProviderConfigured()
=> GetString("VirtualFileResultExecutor_NoFileProviderConfigured");
/// <summary>
/// Type {0} specified by {1} is invalid. Type specified by {1} must derive from {2}.
/// </summary>
internal static string ApplicationPartFactory_InvalidFactoryType
{
get => GetString("ApplicationPartFactory_InvalidFactoryType");
}
/// <summary>
/// Type {0} specified by {1} is invalid. Type specified by {1} must derive from {2}.
/// </summary>
internal static string FormatApplicationPartFactory_InvalidFactoryType(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ApplicationPartFactory_InvalidFactoryType"), p0, p1, p2);
/// <summary>
/// {0} specified on {1} cannot be self referential.
/// </summary>
internal static string RelatedAssemblyAttribute_AssemblyCannotReferenceSelf
{
get => GetString("RelatedAssemblyAttribute_AssemblyCannotReferenceSelf");
}
/// <summary>
/// {0} specified on {1} cannot be self referential.
/// </summary>
internal static string FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("RelatedAssemblyAttribute_AssemblyCannotReferenceSelf"), p0, p1);
/// <summary>
/// Related assembly '{0}' specified by assembly '{1}' could not be found in the directory {2}. Related assemblies must be co-located with the specifying assemblies.
/// </summary>
internal static string RelatedAssemblyAttribute_CouldNotBeFound
{
get => GetString("RelatedAssemblyAttribute_CouldNotBeFound");
}
/// <summary>
/// Related assembly '{0}' specified by assembly '{1}' could not be found in the directory {2}. Related assemblies must be co-located with the specifying assemblies.
/// </summary>
internal static string FormatRelatedAssemblyAttribute_CouldNotBeFound(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("RelatedAssemblyAttribute_CouldNotBeFound"), p0, p1, p2);
/// <summary>
/// Each related assembly must be declared by exactly one assembly. The assembly '{0}' was declared as related assembly by the following:
/// </summary>
internal static string ApplicationAssembliesProvider_DuplicateRelatedAssembly
{
get => GetString("ApplicationAssembliesProvider_DuplicateRelatedAssembly");
}
/// <summary>
/// Each related assembly must be declared by exactly one assembly. The assembly '{0}' was declared as related assembly by the following:
/// </summary>
internal static string FormatApplicationAssembliesProvider_DuplicateRelatedAssembly(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("ApplicationAssembliesProvider_DuplicateRelatedAssembly"), p0);
/// <summary>
/// Assembly '{0}' declared as a related assembly by assembly '{1}' cannot define additional related assemblies.
/// </summary>
internal static string ApplicationAssembliesProvider_RelatedAssemblyCannotDefineAdditional
{
get => GetString("ApplicationAssembliesProvider_RelatedAssemblyCannotDefineAdditional");
}
/// <summary>
/// Assembly '{0}' declared as a related assembly by assembly '{1}' cannot define additional related assemblies.
/// </summary>
internal static string FormatApplicationAssembliesProvider_RelatedAssemblyCannotDefineAdditional(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("ApplicationAssembliesProvider_RelatedAssemblyCannotDefineAdditional"), p0, p1);
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -421,4 +421,19 @@
<data name="VirtualFileResultExecutor_NoFileProviderConfigured" xml:space="preserve">
<value>No file provider has been configured to process the supplied file.</value>
</data>
</root>
<data name="ApplicationPartFactory_InvalidFactoryType" xml:space="preserve">
<value>Type {0} specified by {1} is invalid. Type specified by {1} must derive from {2}.</value>
</data>
<data name="RelatedAssemblyAttribute_AssemblyCannotReferenceSelf" xml:space="preserve">
<value>{0} specified on {1} cannot be self referential.</value>
</data>
<data name="RelatedAssemblyAttribute_CouldNotBeFound" xml:space="preserve">
<value>Related assembly '{0}' specified by assembly '{1}' could not be found in the directory {2}. Related assemblies must be co-located with the specifying assemblies.</value>
</data>
<data name="ApplicationAssembliesProvider_DuplicateRelatedAssembly" xml:space="preserve">
<value>Each related assembly must be declared by exactly one assembly. The assembly '{0}' was declared as related assembly by the following:</value>
</data>
<data name="ApplicationAssembliesProvider_RelatedAssemblyCannotDefineAdditional" xml:space="preserve">
<value>Assembly '{0}' declared as a related assembly by assembly '{1}' cannot define additional related assemblies.</value>
</data>
</root>

View File

@ -13,9 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
public class CompiledRazorAssemblyApplicationPartFactory : ApplicationPartFactory
{
/// <inheritdoc />
public override IEnumerable<ApplicationPart> GetApplicationParts(
Assembly assembly,
string configuration)
public override IEnumerable<ApplicationPart> GetApplicationParts(Assembly assembly, string configuration)
{
if (assembly == null)
{

View File

@ -2,19 +2,41 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Razor.Hosting;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
public class CompiledRazorAssemblyPart : ApplicationPart
/// <summary>
/// An <see cref="ApplicationPart"/> for compiled Razor assemblies.
/// </summary>
public class CompiledRazorAssemblyPart : ApplicationPart, IRazorCompiledItemProvider
{
/// <summary>
/// Initializes a new instance of <see cref="CompiledRazorAssemblyPart"/>.
/// </summary>
/// <param name="assembly">The <see cref="System.Reflection.Assembly"/></param>
public CompiledRazorAssemblyPart(Assembly assembly)
{
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
}
/// <summary>
/// Gets the <see cref="System.Reflection.Assembly"/>.
/// </summary>
public Assembly Assembly { get; }
/// <inheritdoc />
public override string Name => Assembly.GetName().Name;
IEnumerable<RazorCompiledItem> IRazorCompiledItemProvider.CompiledItems
{
get
{
var loader = new RazorCompiledItemLoader();
return loader.LoadItems(Assembly);
}
}
}
}

View File

@ -0,0 +1,19 @@
// 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 Microsoft.AspNetCore.Razor.Hosting;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
/// <summary>
/// Exposes one or more <see cref="RazorCompiledItem"/> instances from an <see cref="ApplicationPart"/>.
/// </summary>
public interface IRazorCompiledItemProvider
{
/// <summary>
/// Gets a sequence of <see cref="RazorCompiledItem"/> instances.
/// </summary>
IEnumerable<RazorCompiledItem> CompiledItems { get; }
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Razor.Hosting;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
internal class RazorCompiledItemFeatureProvider : IApplicationFeatureProvider<ViewsFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ViewsFeature feature)
{
foreach (var provider in parts.OfType<IRazorCompiledItemProvider>())
{
// Ensure parts do not specify views with differing cases. This is not supported
// at runtime and we should flag at as such for precompiled views.
var duplicates = provider.CompiledItems
.GroupBy(i => i.Identifier, StringComparer.OrdinalIgnoreCase)
.FirstOrDefault(g => g.Count() > 1);
if (duplicates != null)
{
var viewsDiffereningInCase = string.Join(Environment.NewLine, duplicates.Select(d => d.Identifier));
var message = string.Join(
Environment.NewLine,
Resources.RazorViewCompiler_ViewPathsDifferOnlyInCase,
viewsDiffereningInCase);
throw new InvalidOperationException(message);
}
foreach (var item in provider.CompiledItems)
{
var descriptor = GetCompiledViewDescriptor(item);
feature.ViewDescriptors.Add(descriptor);
}
}
}
private static CompiledViewDescriptor GetCompiledViewDescriptor(RazorCompiledItem item)
{
var itemAssembly = item.Type.Assembly;
var razorViewAttribute = itemAssembly.GetCustomAttributes<RazorViewAttribute>()
.FirstOrDefault(attribute => attribute.ViewType == item.Type);
return new CompiledViewDescriptor(item, razorViewAttribute);
}
}
}

View File

@ -63,6 +63,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
/// <summary>
/// Gets or sets the <see cref="RazorViewAttribute"/> decorating the view.
/// </summary>
/// <remarks>
/// May be <c>null</c>.
/// </remarks>
public RazorViewAttribute ViewAttribute { get; set; }
/// <summary>

View File

@ -7,136 +7,71 @@ using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Razor.Hosting;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
{
/// <summary>
/// An <see cref="IApplicationFeatureProvider{TFeature}"/> for <see cref="ViewsFeature"/>.
/// </summary>
[Obsolete("This type is obsolete and will be removed in a future version. See " + nameof(IRazorCompiledItemProvider) + " for alternatives.")]
public class ViewsFeatureProvider : IApplicationFeatureProvider<ViewsFeature>
{
public static readonly string PrecompiledViewsAssemblySuffix = ".PrecompiledViews";
public static readonly IReadOnlyList<string> ViewAssemblySuffixes = new string[]
{
PrecompiledViewsAssemblySuffix,
".Views",
};
/// <inheritdoc />
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ViewsFeature feature)
{
var knownIdentifiers = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var descriptors = new List<CompiledViewDescriptor>();
foreach (var assemblyPart in parts.OfType<AssemblyPart>())
{
var attributes = GetViewAttributes(assemblyPart);
var items = LoadItems(assemblyPart);
var viewAttributes = GetViewAttributes(assemblyPart)
.Select(attribute => (Attribute: attribute, RelativePath: ViewPath.NormalizePath(attribute.Path)));
var merged = Merge(items, attributes);
foreach (var item in merged)
var duplicates = viewAttributes.GroupBy(a => a.RelativePath, StringComparer.OrdinalIgnoreCase)
.FirstOrDefault(g => g.Count() > 1);
if (duplicates != null)
{
var descriptor = new CompiledViewDescriptor(item.item, item.attribute);
// We iterate through ApplicationPart instances appear in precendence order.
// If a view path appears in multiple views, we'll use the order to break ties.
if (knownIdentifiers.Add(descriptor.RelativePath))
// Ensure parts do not specify views with differing cases. This is not supported
// at runtime and we should flag at as such for precompiled views.
var viewsDiffereningInCase = string.Join(Environment.NewLine, duplicates.Select(d => d.RelativePath));
var message = string.Join(
Environment.NewLine,
Resources.RazorViewCompiler_ViewPathsDifferOnlyInCase,
viewsDiffereningInCase);
throw new InvalidOperationException(message);
}
foreach (var (attribute, relativePath) in viewAttributes)
{
var viewDescriptor = new CompiledViewDescriptor
{
feature.ViewDescriptors.Add(descriptor);
}
ExpirationTokens = Array.Empty<IChangeToken>(),
RelativePath = relativePath,
ViewAttribute = attribute,
IsPrecompiled = true,
};
feature.ViewDescriptors.Add(viewDescriptor);
}
}
}
private ICollection<(RazorCompiledItem item, RazorViewAttribute attribute)> Merge(
IReadOnlyList<RazorCompiledItem> items,
IEnumerable<RazorViewAttribute> attributes)
{
// This code is a intentionally defensive. We assume that it's possible to have duplicates
// of attributes, and also items that have a single kind of metadata, but not the other.
var dictionary = new Dictionary<string, (RazorCompiledItem item, RazorViewAttribute attribute)>(StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < items.Count; i++)
{
var item = items[i];
if (!dictionary.TryGetValue(item.Identifier, out var entry))
{
dictionary.Add(item.Identifier, (item, null));
}
else if (entry.item == null)
{
dictionary[item.Identifier] = (item, entry.attribute);
}
}
foreach (var attribute in attributes)
{
if (!dictionary.TryGetValue(attribute.Path, out var entry))
{
dictionary.Add(attribute.Path, (null, attribute));
}
else if (entry.attribute == null)
{
dictionary[attribute.Path] = (entry.item, attribute);
}
}
return dictionary.Values;
}
internal virtual IReadOnlyList<RazorCompiledItem> LoadItems(AssemblyPart assemblyPart)
{
if (assemblyPart == null)
{
throw new ArgumentNullException(nameof(assemblyPart));
}
var viewAssembly = assemblyPart.Assembly;
if (viewAssembly != null)
{
var loader = new RazorCompiledItemLoader();
return loader.LoadItems(viewAssembly);
}
return Array.Empty<RazorCompiledItem>();
}
/// <summary>
/// Gets the sequence of <see cref="RazorViewAttribute"/> instances associated with the specified <paramref name="assemblyPart"/>.
/// </summary>
/// <param name="assemblyPart">The <see cref="AssemblyPart"/>.</param>
/// <returns>The sequence of <see cref="RazorViewAttribute"/> instances.</returns>
protected virtual IEnumerable<RazorViewAttribute> GetViewAttributes(AssemblyPart assemblyPart)
{
// We check if the method was overriden by a subclass and preserve the old behavior in that case.
if (GetViewAttributesOverriden())
{
return GetViewAttributesLegacy(assemblyPart);
}
else
{
// It is safe to call this method for additional assembly parts even if there is a feature provider
// present on the pipeline that overrides getviewattributes as dependent parts are later in the list
// of application parts.
return GetViewAttributesFromCurrentAssembly(assemblyPart);
}
bool GetViewAttributesOverriden()
{
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
return GetType() != typeof(ViewsFeatureProvider) &&
GetType().GetMethod(nameof(GetViewAttributes), bindingFlags).DeclaringType != typeof(ViewsFeatureProvider);
}
}
private IEnumerable<RazorViewAttribute> GetViewAttributesLegacy(AssemblyPart assemblyPart)
{
if (assemblyPart == null)
{
throw new ArgumentNullException(nameof(assemblyPart));
}
var featureAssembly = GetViewAssembly(assemblyPart);
var featureAssembly = GetFeatureAssembly(assemblyPart);
if (featureAssembly != null)
{
return featureAssembly.GetCustomAttributes<RazorViewAttribute>();
@ -145,48 +80,34 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
return Enumerable.Empty<RazorViewAttribute>();
}
private Assembly GetViewAssembly(AssemblyPart assemblyPart)
private static Assembly GetFeatureAssembly(AssemblyPart assemblyPart)
{
if (assemblyPart.Assembly.IsDynamic || string.IsNullOrEmpty(assemblyPart.Assembly.Location))
if (assemblyPart.Assembly.IsDynamic || string.IsNullOrEmpty((string)assemblyPart.Assembly.Location))
{
return null;
}
for (var i = 0; i < ViewAssemblySuffixes.Count; i++)
{
var fileName = assemblyPart.Assembly.GetName().Name + ViewAssemblySuffixes[i] + ".dll";
var filePath = Path.Combine(Path.GetDirectoryName(assemblyPart.Assembly.Location), fileName);
var precompiledAssemblyFileName = assemblyPart.Assembly.GetName().Name
+ PrecompiledViewsAssemblySuffix
+ ".dll";
if (File.Exists(filePath))
var precompiledAssemblyFilePath = Path.Combine(
Path.GetDirectoryName(assemblyPart.Assembly.Location),
precompiledAssemblyFileName);
if (File.Exists(precompiledAssemblyFilePath))
{
try
{
try
{
return Assembly.LoadFile(filePath);
}
catch (FileLoadException)
{
// Don't throw if assembly cannot be loaded. This can happen if the file is not a managed assembly.
}
return Assembly.LoadFile(precompiledAssemblyFilePath);
}
catch (FileLoadException)
{
// Don't throw if assembly cannot be loaded. This can happen if the file is not a managed assembly.
}
}
return null;
}
private static IEnumerable<RazorViewAttribute> GetViewAttributesFromCurrentAssembly(AssemblyPart assemblyPart)
{
if (assemblyPart == null)
{
throw new ArgumentNullException(nameof(assemblyPart));
}
var featureAssembly = assemblyPart.Assembly;
if (featureAssembly != null)
{
return featureAssembly.GetCustomAttributes<RazorViewAttribute>();
}
return Enumerable.Empty<RazorViewAttribute>();
}
}
}
}

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
@ -74,10 +75,21 @@ namespace Microsoft.Extensions.DependencyInjection
builder.PartManager.FeatureProviders.Add(new TagHelperFeatureProvider());
}
// ViewFeature items have precedence semantics - when two views have the same path \ identifier,
// the one that appears earlier in the list wins. Therefore the ordering of
// RazorCompiledItemFeatureProvider and ViewsFeatureProvider is pertinent - any view compiled
// using the Sdk will be prefered to views compiled using MvcPrecompilation.
if (!builder.PartManager.FeatureProviders.OfType<RazorCompiledItemFeatureProvider>().Any())
{
builder.PartManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider());
}
#pragma warning disable CS0618 // Type or member is obsolete
if (!builder.PartManager.FeatureProviders.OfType<ViewsFeatureProvider>().Any())
{
builder.PartManager.FeatureProviders.Add(new ViewsFeatureProvider());
}
#pragma warning restore CS0618 // Type or member is obsolete
}
/// <summary>

View File

@ -100,17 +100,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
logger.ViewCompilerLocatedCompiledView(precompiledView.RelativePath);
if (_precompiledViews.TryGetValue(precompiledView.RelativePath, out var otherValue))
if (!_precompiledViews.ContainsKey(precompiledView.RelativePath))
{
var message = string.Join(
Environment.NewLine,
Resources.RazorViewCompiler_ViewPathsDifferOnlyInCase,
otherValue.RelativePath,
precompiledView.RelativePath);
throw new InvalidOperationException(message);
// View ordering has precedence semantics, a view with a higher precedence was
// already added to the list.
_precompiledViews.Add(precompiledView.RelativePath, precompiledView);
}
_precompiledViews.Add(precompiledView.RelativePath, precompiledView);
}
if (_precompiledViews.Count == 0)

View File

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

View File

@ -45,9 +45,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var compileTask = Compiler.CompileAsync(actionDescriptor.RelativePath);
var viewDescriptor = compileTask.GetAwaiter().GetResult();
var pageAttribute = (RazorPageAttribute)viewDescriptor.ViewAttribute;
var context = new PageApplicationModelProviderContext(actionDescriptor, pageAttribute.ViewType.GetTypeInfo());
var context = new PageApplicationModelProviderContext(actionDescriptor, viewDescriptor.Type.GetTypeInfo());
for (var i = 0; i < _applicationModelProviders.Length; i++)
{
_applicationModelProviders[i].OnProvidersExecuting(context);

View File

@ -0,0 +1,436 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyModel;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
public class ApplicationAssembliesProviderTest
{
private static readonly Assembly ThisAssembly = typeof(ApplicationAssembliesProviderTest).Assembly;
[Fact]
public void ResolveAssemblies_ReturnsCurrentAssembly_IfNoDepsFileIsPresent()
{
// Arrange
var provider = new TestApplicationAssembliesProvider();
// Act
var result = provider.ResolveAssemblies(ThisAssembly);
// Assert
Assert.Equal(new[] { ThisAssembly }, result);
}
[Fact]
public void ResolveAssemblies_ReturnsRelatedAssembliesOrderedByName()
{
// Arrange
var assembly1 = typeof(ApplicationAssembliesProvider).Assembly;
var assembly2 = typeof(IActionResult).Assembly;
var assembly3 = typeof(FactAttribute).Assembly;
var relatedAssemblies = new[] { assembly1, assembly2, assembly3 };
var provider = new TestApplicationAssembliesProvider
{
GetRelatedAssembliesDelegate = (assembly) => relatedAssemblies,
};
// Act
var result = provider.ResolveAssemblies(ThisAssembly);
// Assert
Assert.Equal(new[] { ThisAssembly, assembly2, assembly1, assembly3 }, result);
}
[Fact]
public void ResolveAssemblies_ReturnsLibrariesFromTheDepsFileThatReferenceMvc()
{
// Arrange
var mvcAssembly = typeof(IActionResult).Assembly;
var classLibrary = typeof(FactAttribute).Assembly;
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary(ThisAssembly.GetName().Name, new[] { mvcAssembly.GetName().Name, classLibrary.GetName().Name }),
GetLibrary(mvcAssembly.GetName().Name),
GetLibrary(classLibrary.GetName().Name, new[] { mvcAssembly.GetName().Name }),
});
var provider = new TestApplicationAssembliesProvider
{
DependencyContext = dependencyContext,
};
// Act
var result = provider.ResolveAssemblies(ThisAssembly);
// Assert
Assert.Equal(new[] { ThisAssembly, classLibrary, }, result);
}
[Fact]
public void ResolveAssemblies_ReturnsRelatedAssembliesForLibrariesFromDepsFile()
{
// Arrange
var mvcAssembly = typeof(IActionResult).Assembly;
var classLibrary = typeof(object).Assembly;
var relatedPart = typeof(FactAttribute).Assembly;
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary(ThisAssembly.GetName().Name, new[] { relatedPart.GetName().Name, classLibrary.GetName().Name }),
GetLibrary(classLibrary.GetName().Name, new[] { mvcAssembly.GetName().Name }),
GetLibrary(relatedPart.GetName().Name, new[] { mvcAssembly.GetName().Name }),
GetLibrary(mvcAssembly.GetName().Name),
});
var provider = new TestApplicationAssembliesProvider
{
DependencyContext = dependencyContext,
GetRelatedAssembliesDelegate = (assembly) =>
{
if (assembly == classLibrary)
{
return new[] { relatedPart };
}
return Array.Empty<Assembly>();
},
};
// Act
var result = provider.ResolveAssemblies(ThisAssembly);
// Assert
Assert.Equal(new[] { ThisAssembly, classLibrary, relatedPart, }, result);
}
[Fact]
public void ResolveAssemblies_ThrowsIfRelatedAssemblyDefinesAdditionalRelatedAssemblies()
{
// Arrange
var expected = $"Assembly 'TestRelatedAssembly' declared as a related assembly by assembly '{ThisAssembly}' cannot define additional related assemblies.";
var assembly1 = typeof(ApplicationAssembliesProvider).Assembly;
var assembly2 = new TestAssembly();
var relatedAssemblies = new[] { assembly1, assembly2 };
var provider = new TestApplicationAssembliesProvider
{
GetRelatedAssembliesDelegate = (assembly) => relatedAssemblies,
};
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => provider.ResolveAssemblies(ThisAssembly).ToArray());
Assert.Equal(expected, ex.Message);
}
[Fact]
public void ResolveAssemblies_ThrowsIfMultipleAssembliesDeclareTheSameRelatedPart()
{
// Arrange
var mvcAssembly = typeof(IActionResult).Assembly;
var libraryAssembly1 = typeof(object).Assembly;
var libraryAssembly2 = typeof(HttpContext).Assembly;
var relatedPart = typeof(FactAttribute).Assembly;
var expected = string.Join(
Environment.NewLine,
$"Each related assembly must be declared by exactly one assembly. The assembly '{relatedPart.FullName}' was declared as related assembly by the following:",
libraryAssembly1.FullName,
libraryAssembly2.FullName);
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary(ThisAssembly.GetName().Name, new[] { relatedPart.GetName().Name, libraryAssembly1.GetName().Name }),
GetLibrary(libraryAssembly1.GetName().Name, new[] { mvcAssembly.GetName().Name }),
GetLibrary(libraryAssembly2.GetName().Name, new[] { mvcAssembly.GetName().Name }),
GetLibrary(mvcAssembly.GetName().Name),
});
var provider = new TestApplicationAssembliesProvider
{
DependencyContext = dependencyContext,
GetRelatedAssembliesDelegate = (assembly) =>
{
if (assembly == libraryAssembly1 || assembly == libraryAssembly2)
{
return new[] { relatedPart };
}
return Array.Empty<Assembly>();
},
};
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => provider.ResolveAssemblies(ThisAssembly).ToArray());
Assert.Equal(expected, ex.Message);
}
[Fact]
public void CandidateResolver_ThrowsIfDependencyContextContainsDuplicateRuntimeLibraryNames()
{
// Arrange
var upperCaseLibrary = "Microsoft.AspNetCore.Mvc";
var mixedCaseLibrary = "microsoft.aspNetCore.mvc";
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary(mixedCaseLibrary),
GetLibrary(upperCaseLibrary),
});
// Act
var exception = Assert.Throws<InvalidOperationException>(() => ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext));
// Assert
Assert.Equal($"A duplicate entry for library reference {upperCaseLibrary} was found. Please check that all package references in all projects use the same casing for the same package references.", exception.Message);
}
[Fact]
public void GetCandidateLibraries_IgnoresMvcAssemblies()
{
// Arrange
var expected = GetLibrary("SomeRandomAssembly", "Microsoft.AspNetCore.Mvc.Abstractions");
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
expected,
});
// Act
var candidates = ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { expected }, candidates);
}
[Fact]
public void GetCandidateLibraries_DoesNotThrow_IfLibraryDoesNotHaveRuntimeComponent()
{
// Arrange
var expected = GetLibrary("MyApplication", "Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Mvc");
var dependencyContext = GetDependencyContext(new[]
{
expected,
GetLibrary("Microsoft.AspNetCore.Server.Kestrel", "Libuv"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
});
// Act
var candidates = ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext).ToList();
// Assert
Assert.Equal(new[] { expected }, candidates);
}
[Fact]
public void GetCandidateLibraries_ReturnsLibrariesReferencingAnyMvcAssembly()
{
// Arrange
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary("Foo", "Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Bar", "Microsoft.AspNetCore.Mvc"),
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Not.Mvc.Assembly"),
GetLibrary("Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
});
// Act
var candidates = ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { "Foo", "Bar", "Baz" }, candidates.Select(a => a.Name));
}
[Fact]
public void GetCandidateLibraries_LibraryNameComparisonsAreCaseInsensitive()
{
// Arrange
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary("Foo", "MICROSOFT.ASPNETCORE.MVC.CORE"),
GetLibrary("Bar", "microsoft.aspnetcore.mvc"),
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Baz", "mIcRoSoFt.AsPnEtCoRe.MvC.aBsTrAcTiOnS"),
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("LibraryA", "LIBRARYB"),
GetLibrary("LibraryB", "microsoft.aspnetcore.mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Not.Mvc.Assembly"),
GetLibrary("Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
});
// Act
var candidates = ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { "Foo", "Bar", "Baz", "LibraryA", "LibraryB" }, candidates.Select(a => a.Name));
}
[Fact]
public void GetCandidateLibraries_ReturnsLibrariesWithTransitiveReferencesToAnyMvcAssembly()
{
// Arrange
var expectedLibraries = new[] { "Foo", "Bar", "Baz", "LibraryA", "LibraryB", "LibraryC", "LibraryE", "LibraryG", "LibraryH" };
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary("Foo", "Bar"),
GetLibrary("Bar", "Microsoft.AspNetCore.Mvc"),
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Not.Mvc.Assembly"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("LibraryA", "LibraryB"),
GetLibrary("LibraryB","LibraryC"),
GetLibrary("LibraryC", "LibraryD", "Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("LibraryD"),
GetLibrary("LibraryE","LibraryF","LibraryG"),
GetLibrary("LibraryF"),
GetLibrary("LibraryG", "LibraryH"),
GetLibrary("LibraryH", "LibraryI", "Microsoft.AspNetCore.Mvc"),
GetLibrary("LibraryI"),
});
// Act
var candidates = ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(expectedLibraries, candidates.Select(a => a.Name));
}
[Fact]
public void GetCandidateLibraries_SkipsMvcAssemblies()
{
// Arrange
var dependencyContext = GetDependencyContext(new[]
{
GetLibrary("MvcSandbox", "Microsoft.AspNetCore.Mvc.Core", "Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Core", "Microsoft.AspNetCore.HttpAbstractions"),
GetLibrary("Microsoft.AspNetCore.HttpAbstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc", "Microsoft.AspNetCore.Mvc.Abstractions", "Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc.TagHelpers", "Microsoft.AspNetCore.Mvc.Razor"),
GetLibrary("Microsoft.AspNetCore.Mvc.Razor"),
GetLibrary("ControllersAssembly", "Microsoft.AspNetCore.Mvc"),
});
// Act
var candidates = ApplicationAssembliesProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { "MvcSandbox", "ControllersAssembly" }, candidates.Select(a => a.Name));
}
// This test verifies DefaultAssemblyPartDiscoveryProvider.ReferenceAssemblies reflects the actual loadable assemblies
// of the libraries that Microsoft.AspNetCore.Mvc depends on.
// If we add or remove dependencies, this test should be changed together.
[Fact]
public void ReferenceAssemblies_ReturnsLoadableReferenceAssemblies()
{
// Arrange
var excludeAssemblies = new string[]
{
"Microsoft.AspNetCore.Mvc.Core.Test",
"Microsoft.AspNetCore.Mvc.TestCommon",
"Microsoft.AspNetCore.Mvc.TestDiagnosticListener",
"Microsoft.AspNetCore.Mvc.WebApiCompatShim",
};
var additionalAssemblies = new[]
{
// The following assemblies are not reachable from Microsoft.AspNetCore.Mvc
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
};
var dependencyContextLibraries = DependencyContext.Load(ThisAssembly)
.CompileLibraries
.Where(r => r.Name.StartsWith("Microsoft.AspNetCore.Mvc", StringComparison.OrdinalIgnoreCase) &&
!excludeAssemblies.Contains(r.Name, StringComparer.OrdinalIgnoreCase))
.Select(r => r.Name);
var expected = dependencyContextLibraries
.Concat(additionalAssemblies)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase);
// Act
var referenceAssemblies = ApplicationAssembliesProvider
.ReferenceAssemblies
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase);
// Assert
Assert.Equal(expected, referenceAssemblies, StringComparer.OrdinalIgnoreCase);
}
private class TestApplicationAssembliesProvider : ApplicationAssembliesProvider
{
public DependencyContext DependencyContext { get; set; }
public Func<Assembly, IReadOnlyList<Assembly>> GetRelatedAssembliesDelegate { get; set; } = (assembly) => Array.Empty<Assembly>();
protected override DependencyContext LoadDependencyContext(Assembly assembly) => DependencyContext;
protected override IReadOnlyList<Assembly> GetRelatedAssemblies(Assembly assembly) => GetRelatedAssembliesDelegate(assembly);
protected override IEnumerable<Assembly> GetLibraryAssemblies(DependencyContext dependencyContext, RuntimeLibrary runtimeLibrary)
{
var assemblyName = new AssemblyName(runtimeLibrary.Name);
yield return Assembly.Load(assemblyName);
}
}
private static DependencyContext GetDependencyContext(RuntimeLibrary[] libraries)
{
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
libraries,
Enumerable.Empty<RuntimeFallbacks>());
return dependencyContext;
}
private static RuntimeLibrary GetLibrary(string name, params string[] dependencyNames)
{
var dependencies = dependencyNames?.Select(d => new Dependency(d, "42.0.0")) ?? new Dependency[0];
return new RuntimeLibrary(
"package",
name,
"23.0.0",
"hash",
new RuntimeAssetGroup[0],
new RuntimeAssetGroup[0],
new ResourceAssembly[0],
dependencies: dependencies.ToArray(),
serviceable: true);
}
private class TestAssembly : Assembly
{
public override string FullName => "TestRelatedAssembly";
public override bool IsDefined(Type attributeType, bool inherit)
{
return attributeType == typeof(RelatedAssemblyAttribute);
}
}
}
}

View File

@ -24,7 +24,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
new ControllersFeatureProvider((f, v) => f.Values.Add($"ControllersFeatureProvider2{v}")));
var feature = new ControllersFeature();
var expectedResults = new[] {
var expectedResults = new[]
{
"ControllersFeatureProvider1ControllersPartA",
"ControllersFeatureProvider1ControllersPartC",
"ControllersFeatureProvider2ControllersPartA",

View File

@ -0,0 +1,104 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
public class RelatedAssemblyPartTest
{
private static readonly string AssemblyDirectory = Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar);
[Fact]
public void GetRelatedAssemblies_Noops_ForDynamicAssemblies()
{
// Arrange
var name = new AssemblyName($"DynamicAssembly-{Guid.NewGuid()}");
var assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect);
// Act
var result = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true);
// Assert
Assert.Empty(result);
}
[Fact]
public void GetRelatedAssemblies_ThrowsIfRelatedAttributeReferencesSelf()
{
// Arrange
var expected = "RelatedAssemblyAttribute specified on MyAssembly cannot be self referential.";
var assembly = new TestAssembly { AttributeAssembly = "MyAssembly" };
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true));
Assert.Equal(expected, ex.Message);
}
[Fact]
public void GetRelatedAssemblies_ThrowsIfAssemblyCannotBeFound()
{
// Arrange
var expected = $"Related assembly 'DoesNotExist' specified by assembly 'MyAssembly' could not be found in the directory {AssemblyDirectory}. Related assemblies must be co-located with the specifying assemblies.";
var assemblyPath = Path.Combine(AssemblyDirectory, "MyAssembly.dll");
var assembly = new TestAssembly
{
AttributeAssembly = "DoesNotExist"
};
// Act & Assert
var ex = Assert.Throws<FileNotFoundException>(() => RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true));
Assert.Equal(expected, ex.Message);
Assert.Equal(Path.Combine(AssemblyDirectory, "DoesNotExist.dll"), ex.FileName);
}
[Fact]
public void GetRelatedAssemblies_LoadsRelatedAssembly()
{
// Arrange
var destination = Path.Combine(AssemblyDirectory, "RelatedAssembly.dll");
var assembly = new TestAssembly
{
AttributeAssembly = "RelatedAssembly",
};
var relatedAssembly = typeof(RelatedAssemblyPartTest).Assembly;
try
{
File.WriteAllBytes(destination, new byte[0]);
var result = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true, file =>
{
Assert.Equal(file, destination);
return relatedAssembly;
});
Assert.Equal(new[] { relatedAssembly }, result);
}
finally
{
File.Delete(destination);
}
}
private class TestAssembly : Assembly
{
public override AssemblyName GetName()
{
return new AssemblyName("MyAssembly");
}
public string AttributeAssembly { get; set; }
public override string CodeBase => Path.Combine(AssemblyDirectory, "MyAssembly.dll");
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
var attribute = new RelatedAssemblyAttribute(AttributeAssembly);
return new[] { attribute };
}
}
}
}

View File

@ -1,501 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Extensions.DependencyModel;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Internal
{
public class DefaultAssemblyPartDiscoveryProviderTests
{
private static readonly Assembly CurrentAssembly =
typeof(DefaultAssemblyPartDiscoveryProviderTests).GetTypeInfo().Assembly;
[Fact]
public void CandidateResolver_ThrowsIfDependencyContextContainsDuplicateRuntimeLibraryNames()
{
// Arrange
var upperCaseLibrary = "Microsoft.AspNetCore.Mvc";
var mixedCaseLibrary = "microsoft.aspNetCore.mvc";
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
new[]
{
GetLibrary(mixedCaseLibrary),
GetLibrary(upperCaseLibrary),
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var exception = Assert.Throws<InvalidOperationException>(() => DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(dependencyContext));
// Assert
Assert.Equal($"A duplicate entry for library reference {upperCaseLibrary} was found. Please check that all package references in all projects use the same casing for the same package references.", exception.Message);
}
[Fact]
public void GetCandidateLibraries_IgnoresMvcAssemblies()
{
// Arrange
var expected = GetLibrary("SomeRandomAssembly", "Microsoft.AspNetCore.Mvc.Abstractions");
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
new[]
{
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
expected,
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { expected }, candidates);
}
[Theory]
[MemberData(nameof(ResolveAdditionalReferencesData))]
public void ResolveAdditionalReferences_DiscoversAdditionalReferences(ResolveAdditionalReferencesTestData testData)
{
// Arrange
var resolver = testData.AssemblyResolver;
DefaultAssemblyPartDiscoveryProvider.AssemblyResolver = path => resolver.ContainsKey(path);
DefaultAssemblyPartDiscoveryProvider.AssemblyLoader = path => resolver.TryGetValue(path, out var result) ? result : null;
// Arrange & Act
var (additionalReferences, entryAssemblyAdditionalReferences) =
DefaultAssemblyPartDiscoveryProvider.ResolveAdditionalReferences(testData.EntryAssembly, testData.CandidateAssemblies);
var additionalRefs = additionalReferences.Select(a => a.FullName).OrderBy(id => id).ToArray();
var entryAssemblyAdditionalRefs = entryAssemblyAdditionalReferences.Select(a => a.FullName).OrderBy(id => id).ToArray();
// Assert
Assert.Equal(testData.ExpectedAdditionalReferences, additionalRefs);
Assert.Equal(testData.ExpectedEntryAssemblyAdditionalReferences, entryAssemblyAdditionalRefs);
}
public class ResolveAdditionalReferencesTestData
{
public Assembly EntryAssembly { get; set; }
public SortedSet<Assembly> CandidateAssemblies { get; set; }
public IDictionary<string, Assembly> AssemblyResolver { get; set; }
public string[] ExpectedAdditionalReferences { get; set; }
public string[] ExpectedEntryAssemblyAdditionalReferences { get; set; }
}
public static TheoryData<ResolveAdditionalReferencesTestData> ResolveAdditionalReferencesData
{
get
{
var data = new TheoryData<ResolveAdditionalReferencesTestData>();
var noCandidates = Array.Empty<Assembly>();
var noResolvable = new Dictionary<string, Assembly>();
var noAdditionalReferences = new string[] { };
// Single assembly app no precompilation
var aAssembly = new DiscoveryTestAssembly("A");
var singleAppNoPrecompilation = new ResolveAdditionalReferencesTestData
{
EntryAssembly = aAssembly,
CandidateAssemblies = CreateCandidates(aAssembly),
AssemblyResolver = noResolvable,
ExpectedAdditionalReferences = Array.Empty<string>(),
ExpectedEntryAssemblyAdditionalReferences = Array.Empty<string>()
};
data.Add(singleAppNoPrecompilation);
// Single assembly app with old precompilation not included in the graph
var bAssembly = new DiscoveryTestAssembly("B");
var (bPath, bPrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("B");
var singleAssemblyPrecompilationNotInGraph = new ResolveAdditionalReferencesTestData
{
EntryAssembly = bAssembly,
CandidateAssemblies = CreateCandidates(bAssembly),
AssemblyResolver = new Dictionary<string, Assembly> { [bPath] = bPrecompiledViews },
ExpectedAdditionalReferences = noAdditionalReferences,
ExpectedEntryAssemblyAdditionalReferences = new[] { bPrecompiledViews.FullName }
};
data.Add(singleAssemblyPrecompilationNotInGraph);
//// Single assembly app with new precompilation not included in the graph
var cAssembly = new DiscoveryTestAssembly(
"C",
DiscoveryTestAssembly.DefaultLocationBase,
new[] { ("C.PrecompiledViews.dll", true) });
var (cPath, cPrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("C");
var singleAssemblyNewPrecompilationNotInGraph = new ResolveAdditionalReferencesTestData
{
EntryAssembly = cAssembly,
CandidateAssemblies = CreateCandidates(cAssembly),
AssemblyResolver = new Dictionary<string, Assembly> { [cPath] = cPrecompiledViews },
ExpectedAdditionalReferences = noAdditionalReferences,
ExpectedEntryAssemblyAdditionalReferences = new[] { cPrecompiledViews.FullName }
};
data.Add(singleAssemblyNewPrecompilationNotInGraph);
//// Single assembly app with new precompilation included in the graph
var dAssembly = new DiscoveryTestAssembly(
"D",
DiscoveryTestAssembly.DefaultLocationBase,
new[] { (Path.Combine(DiscoveryTestAssembly.DefaultLocationBase, "subfolder", "D.PrecompiledViews.dll"), true) });
var (dPath, dPrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("D");
var singleAssemblyNewPrecompilationInGraph = new ResolveAdditionalReferencesTestData
{
EntryAssembly = dAssembly,
CandidateAssemblies = CreateCandidates(dAssembly, dPrecompiledViews),
AssemblyResolver = new Dictionary<string, Assembly> { [dPath] = dPrecompiledViews },
ExpectedAdditionalReferences = noAdditionalReferences,
ExpectedEntryAssemblyAdditionalReferences = new[] { dPrecompiledViews.FullName }
};
data.Add(singleAssemblyNewPrecompilationInGraph);
//// Single assembly app with new precompilation included in the graph optional part
var hAssembly = new DiscoveryTestAssembly(
"h",
DiscoveryTestAssembly.DefaultLocationBase,
new[] { ("H.PrecompiledViews.dll", false) });
var (hPath, hPrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("H");
var singleAssemblyNewPrecompilationInGraphOptionalDependency = new ResolveAdditionalReferencesTestData
{
EntryAssembly = hAssembly,
CandidateAssemblies = CreateCandidates(hAssembly, hPrecompiledViews),
AssemblyResolver = new Dictionary<string, Assembly> { [hPath] = hPrecompiledViews },
ExpectedAdditionalReferences = noAdditionalReferences,
ExpectedEntryAssemblyAdditionalReferences = noAdditionalReferences
};
data.Add(singleAssemblyNewPrecompilationInGraphOptionalDependency);
//// Entry assembly with two dependencies app with new precompilation included in the graph
var eAssembly = new DiscoveryTestAssembly(
"E",
DiscoveryTestAssembly.DefaultLocationBase,
new[] { ("E.PrecompiledViews.dll", true) });
var (ePath, ePrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("E");
var fAssembly = new DiscoveryTestAssembly(
"F",
DiscoveryTestAssembly.DefaultLocationBase,
new[] { ("F.PrecompiledViews.dll", true) });
var (fPath, fPrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("F");
var gAssembly = new DiscoveryTestAssembly(
"G",
DiscoveryTestAssembly.DefaultLocationBase,
new[] { (Path.Combine(DiscoveryTestAssembly.DefaultLocationBase, "subfolder", "G.PrecompiledViews.dll"), true) });
var (gPath, gPrecompiledViews) = CreateResolvablePrecompiledViewsAssembly("G");
var multipleAssembliesNewPrecompilationInGraph = new ResolveAdditionalReferencesTestData
{
EntryAssembly = gAssembly,
CandidateAssemblies = CreateCandidates(
fAssembly,
fPrecompiledViews,
gAssembly,
gPrecompiledViews,
eAssembly,
ePrecompiledViews),
AssemblyResolver = new Dictionary<string, Assembly> {
[ePath] = ePrecompiledViews,
[fPath] = fPrecompiledViews,
[gPath] = gPrecompiledViews
},
ExpectedAdditionalReferences = new[] { ePrecompiledViews.FullName, fPrecompiledViews.FullName },
ExpectedEntryAssemblyAdditionalReferences = new[] {
gPrecompiledViews.FullName
}
};
data.Add(multipleAssembliesNewPrecompilationInGraph);
return data;
}
}
private static SortedSet<Assembly> CreateCandidates(params Assembly[] assemblies) =>
new SortedSet<Assembly>(assemblies, DefaultAssemblyPartDiscoveryProvider.FullNameAssemblyComparer.Instance);
private static (string, Assembly) CreateResolvablePrecompiledViewsAssembly(string name, string path = null) =>
(path ?? Path.Combine(DiscoveryTestAssembly.DefaultLocationBase, $"{name}.PrecompiledViews.dll"),
new DiscoveryTestAssembly($"{name}.PrecompiledViews"));
[Fact]
public void GetCandidateLibraries_DoesNotThrow_IfLibraryDoesNotHaveRuntimeComponent()
{
// Arrange
var expected = GetLibrary("MyApplication", "Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Mvc");
var deps = new DependencyContext(
new TargetInfo("netcoreapp2.0", "rurntime", "signature", isPortable: true),
CompilationOptions.Default,
Enumerable.Empty<CompilationLibrary>(),
new[]
{
expected,
GetLibrary("Microsoft.AspNetCore.Server.Kestrel", "Libuv"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(deps).ToList();
// Assert
Assert.Equal(new[] { expected }, candidates);
}
[Fact]
public void CandidateAssemblies_ReturnsEntryAssemblyIfDependencyContextIsNull()
{
// Arrange & Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateAssemblies(CurrentAssembly, dependencyContext: null);
// Assert
Assert.Equal(new[] { CurrentAssembly }, candidates);
}
[Fact]
public void GetCandidateLibraries_ReturnsLibrariesReferencingAnyMvcAssembly()
{
// Arrange
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
new[]
{
GetLibrary("Foo", "Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Bar", "Microsoft.AspNetCore.Mvc"),
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Not.Mvc.Assembly"),
GetLibrary("Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { "Foo", "Bar", "Baz" }, candidates.Select(a => a.Name));
}
[Fact]
public void GetCandidateLibraries_LibraryNameComparisonsAreCaseInsensitive()
{
// Arrange
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
new[]
{
GetLibrary("Foo", "MICROSOFT.ASPNETCORE.MVC.CORE"),
GetLibrary("Bar", "microsoft.aspnetcore.mvc"),
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Baz", "mIcRoSoFt.AsPnEtCoRe.MvC.aBsTrAcTiOnS"),
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("LibraryA", "LIBRARYB"),
GetLibrary("LibraryB", "microsoft.aspnetcore.mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Not.Mvc.Assembly"),
GetLibrary("Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { "Foo", "Bar", "Baz", "LibraryA", "LibraryB" }, candidates.Select(a => a.Name));
}
[Fact]
public void GetCandidateLibraries_ReturnsLibrariesWithTransitiveReferencesToAnyMvcAssembly()
{
// Arrange
var expectedLibraries = new[] { "Foo", "Bar", "Baz", "LibraryA", "LibraryB", "LibraryC", "LibraryE", "LibraryG", "LibraryH" };
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
new[]
{
GetLibrary("Foo", "Bar"),
GetLibrary("Bar", "Microsoft.AspNetCore.Mvc"),
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc"),
GetLibrary("Not.Mvc.Assembly"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Unofficial.Microsoft.AspNetCore.Mvc"),
GetLibrary("LibraryA", "LibraryB"),
GetLibrary("LibraryB","LibraryC"),
GetLibrary("LibraryC", "LibraryD", "Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("LibraryD"),
GetLibrary("LibraryE","LibraryF","LibraryG"),
GetLibrary("LibraryF"),
GetLibrary("LibraryG", "LibraryH"),
GetLibrary("LibraryH", "LibraryI", "Microsoft.AspNetCore.Mvc"),
GetLibrary("LibraryI")
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(expectedLibraries, candidates.Select(a => a.Name));
}
[Fact]
public void GetCandidateLibraries_SkipsMvcAssemblies()
{
// Arrange
var dependencyContext = new DependencyContext(
new TargetInfo("framework", "runtime", "signature", isPortable: true),
CompilationOptions.Default,
new CompilationLibrary[0],
new[]
{
GetLibrary("MvcSandbox", "Microsoft.AspNetCore.Mvc.Core", "Microsoft.AspNetCore.Mvc"),
GetLibrary("Microsoft.AspNetCore.Mvc.Core", "Microsoft.AspNetCore.HttpAbstractions"),
GetLibrary("Microsoft.AspNetCore.HttpAbstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc", "Microsoft.AspNetCore.Mvc.Abstractions", "Microsoft.AspNetCore.Mvc.Core"),
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
GetLibrary("Microsoft.AspNetCore.Mvc.TagHelpers", "Microsoft.AspNetCore.Mvc.Razor"),
GetLibrary("Microsoft.AspNetCore.Mvc.Razor"),
GetLibrary("ControllersAssembly", "Microsoft.AspNetCore.Mvc"),
},
Enumerable.Empty<RuntimeFallbacks>());
// Act
var candidates = DefaultAssemblyPartDiscoveryProvider.GetCandidateLibraries(dependencyContext);
// Assert
Assert.Equal(new[] { "MvcSandbox", "ControllersAssembly" }, candidates.Select(a => a.Name));
}
// This test verifies DefaultAssemblyPartDiscoveryProvider.ReferenceAssemblies reflects the actual loadable assemblies
// of the libraries that Microsoft.AspNetCore.Mvc depends on.
// If we add or remove dependencies, this test should be changed together.
[Fact]
public void ReferenceAssemblies_ReturnsLoadableReferenceAssemblies()
{
// Arrange
var excludeAssemblies = new string[]
{
"Microsoft.AspNetCore.Mvc.Core.Test",
"Microsoft.AspNetCore.Mvc.TestCommon",
"Microsoft.AspNetCore.Mvc.TestDiagnosticListener",
"Microsoft.AspNetCore.Mvc.WebApiCompatShim",
};
var additionalAssemblies = new[]
{
// The following assemblies are not reachable from Microsoft.AspNetCore.Mvc
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
"Microsoft.AspnetCore.All",
};
var dependencyContextLibraries = DependencyContext.Load(CurrentAssembly)
.RuntimeLibraries
.Where(r => r.Name.StartsWith("Microsoft.AspNetCore.Mvc", StringComparison.OrdinalIgnoreCase) &&
!excludeAssemblies.Contains(r.Name, StringComparer.OrdinalIgnoreCase))
.Select(r => r.Name);
var expected = dependencyContextLibraries
.Concat(additionalAssemblies)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase);
// Act
var referenceAssemblies = DefaultAssemblyPartDiscoveryProvider
.ReferenceAssemblies
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase);
// Assert
Assert.Equal(expected, referenceAssemblies, StringComparer.OrdinalIgnoreCase);
}
private static RuntimeLibrary GetLibrary(string name, params string[] dependencyNames)
{
var dependencies = dependencyNames?.Select(d => new Dependency(d, "42.0.0")) ?? new Dependency[0];
return new RuntimeLibrary(
"package",
name,
"23.0.0",
"hash",
new RuntimeAssetGroup[0],
new RuntimeAssetGroup[0],
new ResourceAssembly[0],
dependencies: dependencies.ToArray(),
serviceable: true);
}
private class DiscoveryTestAssembly : Assembly
{
private readonly string _fullName;
private readonly string _location;
private readonly Attribute[] _additionalDependencies;
public static readonly string DefaultLocationBase =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"c:\app\" : "/app/";
public DiscoveryTestAssembly(string fullName, string location = null)
: this(
fullName,
location ?? Path.Combine(DefaultLocationBase, new AssemblyName(fullName).Name + ".dll"),
Array.Empty<(string, bool)>())
{ }
public DiscoveryTestAssembly(string fullName, string location, IEnumerable<(string, bool)> additionalDependencies)
{
_fullName = fullName;
_location = location;
_additionalDependencies = additionalDependencies
.Select(ad => new AssemblyMetadataAttribute(
"Microsoft.AspNetCore.Mvc.AdditionalReference",
$"{ad.Item1},{ad.Item2}")).ToArray();
}
public override string FullName => _fullName;
public override string Location => _location;
public override object[] GetCustomAttributes(bool inherit) => _additionalDependencies;
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
var attributes = _additionalDependencies
.Where(t => t.GetType().IsAssignableFrom(attributeType))
.ToArray();
var result = Array.CreateInstance(attributeType, attributes.Length);
attributes.CopyTo(result, 0);
return (object[])result;
}
public override AssemblyName GetName(bool copiedName) => new AssemblyName(FullName);
public override AssemblyName GetName() => new AssemblyName(FullName);
}
}
}

View File

@ -64,5 +64,18 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("Hello from runtime-compiled rzc view!", responseBody.Trim());
}
[Fact]
public async Task RzcViewsArePreferredToPrecompiledViews()
{
// Verifies that when two views have the same paths, the one compiled using rzc is preferred to the one from Precompilation.
// Act
var response = await Client.GetAsync("http://localhost/Common/View");
var responseBody = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("Hello from buildtime-compiled rzc view!", responseBody.Trim());
}
}
}

View File

@ -0,0 +1,131 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Razor.Hosting;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
{
public class RazorCompiledItemFeatureProviderTest
{
[Fact]
public void PopulateFeature_AddsItemsFromProviderTypes()
{
// Arrange
var item1 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item1" && i.Type == typeof(TestView));
var item2 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item2" && i.Type == typeof(TestPage));
var part1 = new AssemblyPart(typeof(RazorCompiledItemFeatureProviderTest).Assembly);
var part2 = new Mock<ApplicationPart>();
part2
.As<IRazorCompiledItemProvider>()
.Setup(p => p.CompiledItems).Returns(new[] { item1, item2, });
var featureProvider = new RazorCompiledItemFeatureProvider();
var feature = new ViewsFeature();
// Act
featureProvider.PopulateFeature(new[] { part1, part2.Object }, feature);
// Assert
Assert.Equal(new[] { item1, item2 }, feature.ViewDescriptors.Select(d => d.Item));
}
[Fact]
public void PopulateFeature_PopulatesRazorViewAttributeFromTypeAssembly()
{
// Arrange
var item1 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item1" && i.Type == typeof(TestView));
var item2 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item2" && i.Type == typeof(TestPage));
var attribute1 = new RazorViewAttribute("Item1", typeof(TestView));
var attribute2 = new RazorViewAttribute("Item2", typeof(TestPage));
var assembly = new TestAssembly(new[] { attribute1, attribute2 });
var part1 = new AssemblyPart(assembly);
var part2 = new Mock<ApplicationPart>();
part2
.As<IRazorCompiledItemProvider>()
.Setup(p => p.CompiledItems).Returns(new[] { item1, item2, });
var featureProvider = new RazorCompiledItemFeatureProvider();
var feature = new ViewsFeature();
// Act
featureProvider.PopulateFeature(new[] { part1, part2.Object }, feature);
// Assert
Assert.Equal(new[] { item1, item2 }, feature.ViewDescriptors.Select(d => d.Item));
}
[Fact]
public void PopulateFeature_AllowsDuplicateItemsFromMultipleParts()
{
// Arrange
var item1 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item" && i.Type == typeof(TestView));
var item2 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item" && i.Type == typeof(TestPage));
var part1 = new Mock<ApplicationPart>();
part1
.As<IRazorCompiledItemProvider>()
.Setup(p => p.CompiledItems).Returns(new[] { item1, });
var part2 = new Mock<ApplicationPart>();
part2
.As<IRazorCompiledItemProvider>()
.Setup(p => p.CompiledItems).Returns(new[] { item2, });
var featureProvider = new RazorCompiledItemFeatureProvider();
var feature = new ViewsFeature();
// Act
featureProvider.PopulateFeature(new[] { part1.Object, part2.Object }, feature);
// Assert
Assert.Equal(new[] { item1, item2 }, feature.ViewDescriptors.Select(d => d.Item));
}
[Fact]
public void PopulateFeature_ThrowsIfTwoItemsFromSamePart_OnlyDifferInCase()
{
// Arrange
var item1 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "Item");
var item2 = Mock.Of<RazorCompiledItem>(i => i.Identifier == "item");
var expected = string.Join(
Environment.NewLine,
"The following precompiled view paths differ only in case, which is not supported:",
"Item",
"item");
var part1 = new AssemblyPart(typeof(RazorCompiledItemFeatureProviderTest).Assembly);
var part2 = new Mock<ApplicationPart>();
part2
.As<IRazorCompiledItemProvider>()
.Setup(p => p.CompiledItems).Returns(new[] { item1, item2, });
var featureProvider = new RazorCompiledItemFeatureProvider();
var feature = new ViewsFeature();
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => featureProvider.PopulateFeature(new[] { part1, part2.Object }, feature));
Assert.Equal(expected, ex.Message);
}
private class TestAssembly : Assembly
{
private readonly object[] _attributes;
public TestAssembly(object[] attributes)
{
_attributes = attributes;
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
return _attributes;
}
}
private class TestView { }
private class TestPage { }
}
}

View File

@ -6,27 +6,26 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Razor.Hosting;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
{
#pragma warning disable CS0618 // Type or member is obsolete
public class ViewsFeatureProviderTest
{
[Fact]
public void PopulateFeature_ReturnsEmptySequenceIfNoAssemblyPartHasViewAssembly()
{
// Arrange
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(new AssemblyPart(typeof(ViewsFeatureProviderTest).Assembly));
partManager.FeatureProviders.Add(new ViewsFeatureProvider());
var applicationPartManager = new ApplicationPartManager();
applicationPartManager.ApplicationParts.Add(
new AssemblyPart(typeof(ViewsFeatureProviderTest).GetTypeInfo().Assembly));
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
applicationPartManager.PopulateFeature(feature);
// Assert
Assert.Empty(feature.ViewDescriptors);
@ -36,31 +35,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
public void PopulateFeature_ReturnsViewsFromAllAvailableApplicationParts()
{
// Arrange
var part1 = new AssemblyPart(typeof(object).Assembly);
var part2 = new AssemblyPart(GetType().Assembly);
var items = new Dictionary<AssemblyPart, IReadOnlyList<RazorCompiledItem>>
{
{
part1,
new[]
{
new TestRazorCompiledItem(typeof(object), "mvc.1.0.view", "/Views/test/Index.cshtml", new object[]{ }),
// This one doesn't have a RazorViewAttribute
new TestRazorCompiledItem(typeof(StringBuilder), "mvc.1.0.view", "/Views/test/About.cshtml", new object[]{ }),
}
},
{
part2,
new[]
{
new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", "/Areas/Admin/Views/Index.cshtml", new object[]{ }),
}
},
};
var attributes = new Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>>
var part1 = new AssemblyPart(typeof(object).GetTypeInfo().Assembly);
var part2 = new AssemblyPart(GetType().GetTypeInfo().Assembly);
var featureProvider = new TestableViewsFeatureProvider(new Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>>
{
{
part1,
@ -74,105 +51,71 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
new[]
{
new RazorViewAttribute("/Areas/Admin/Views/Index.cshtml", typeof(string)),
// This one doesn't have a RazorCompiledItem
new RazorViewAttribute("/Areas/Admin/Views/About.cshtml", typeof(int)),
}
},
};
});
var featureProvider = new TestableViewsFeatureProvider(items, attributes);
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(part1);
partManager.ApplicationParts.Add(part2);
partManager.FeatureProviders.Add(featureProvider);
var applicationPartManager = new ApplicationPartManager();
applicationPartManager.ApplicationParts.Add(part1);
applicationPartManager.ApplicationParts.Add(part2);
applicationPartManager.FeatureProviders.Add(featureProvider);
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
applicationPartManager.PopulateFeature(feature);
// Assert
Assert.Collection(feature.ViewDescriptors.OrderBy(f => f.RelativePath, StringComparer.Ordinal),
view =>
{
Assert.Empty(view.ExpirationTokens);
Assert.True(view.IsPrecompiled);
Assert.Null(view.Item);
Assert.Equal("/Areas/Admin/Views/About.cshtml", view.RelativePath);
Assert.Equal(typeof(int), view.Type);
Assert.Equal("/Areas/Admin/Views/About.cshtml", view.ViewAttribute.Path);
Assert.Equal(typeof(int), view.ViewAttribute.ViewType);
},
view =>
{
// This one doesn't have a RazorCompiledItem
Assert.Empty(view.ExpirationTokens);
Assert.True(view.IsPrecompiled);
Assert.Equal("/Areas/Admin/Views/Index.cshtml", view.Item.Identifier);
Assert.Equal("mvc.1.0.view", view.Item.Kind);
Assert.Equal(typeof(string), view.Item.Type);
Assert.Equal("/Areas/Admin/Views/Index.cshtml", view.RelativePath);
Assert.Equal(typeof(string), view.Type);
Assert.Equal("/Areas/Admin/Views/Index.cshtml", view.ViewAttribute.Path);
Assert.Equal(typeof(string), view.ViewAttribute.ViewType);
},
view =>
{
// This one doesn't have a RazorViewAttribute
Assert.Empty(view.ExpirationTokens);
Assert.True(view.IsPrecompiled);
Assert.Equal("/Views/test/About.cshtml", view.Item.Identifier);
Assert.Equal("mvc.1.0.view", view.Item.Kind);
Assert.Equal(typeof(StringBuilder), view.Item.Type);
Assert.Equal("/Views/test/About.cshtml", view.RelativePath);
Assert.Equal(typeof(StringBuilder), view.Type);
Assert.Null(view.ViewAttribute);
},
view =>
{
Assert.Empty(view.ExpirationTokens);
Assert.True(view.IsPrecompiled);
Assert.Equal("/Views/test/Index.cshtml", view.Item.Identifier);
Assert.Equal("mvc.1.0.view", view.Item.Kind);
Assert.Equal(typeof(object), view.Item.Type);
Assert.Equal("/Views/test/Index.cshtml", view.RelativePath);
Assert.Equal(typeof(object), view.Type);
Assert.Equal("/Views/test/Index.cshtml", view.ViewAttribute.Path);
Assert.Equal(typeof(object), view.ViewAttribute.ViewType);
});
}
[Fact]
public void PopulateFeature_PrefersViewsFromPartsWithHigherPrecedence()
public void PopulateFeature_ThrowsIfSingleAssemblyContainsMultipleAttributesWithTheSamePath()
{
// Arrange
var part1 = new AssemblyPart(typeof(ViewsFeatureProvider).Assembly);
var item1 = new TestRazorCompiledItem(typeof(StringBuilder), "mvc.1.0.view", "/Areas/Admin/Views/Shared/_Layout.cshtml", new object[] { });
var part2 = new AssemblyPart(GetType().Assembly);
var item2 = new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", "/Areas/Admin/Views/Shared/_Layout.cshtml", new object[] { });
var item3 = new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", "/Areas/Admin/Views/Shared/_Partial.cshtml", new object[] { });
var items = new Dictionary<AssemblyPart, IReadOnlyList<RazorCompiledItem>>
var path1 = "/Views/test/Index.cshtml";
var path2 = "/views/test/index.cshtml";
var expected = string.Join(
Environment.NewLine,
"The following precompiled view paths differ only in case, which is not supported:",
path1,
path2);
var part = new AssemblyPart(typeof(object).GetTypeInfo().Assembly);
var featureProvider = new TestableViewsFeatureProvider(new Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>>
{
{ part1, new[] { item1 } },
{ part2, new[] { item2, item3, } },
};
{
part,
new[]
{
new RazorViewAttribute(path1, typeof(object)),
new RazorViewAttribute(path2, typeof(object)),
}
},
});
var featureProvider = new TestableViewsFeatureProvider(items, attributes: new Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>>());
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(part1);
partManager.ApplicationParts.Add(part2);
partManager.FeatureProviders.Add(featureProvider);
var applicationPartManager = new ApplicationPartManager();
applicationPartManager.ApplicationParts.Add(part);
applicationPartManager.FeatureProviders.Add(featureProvider);
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
// Assert
Assert.Collection(feature.ViewDescriptors.OrderBy(f => f.RelativePath, StringComparer.Ordinal),
view => Assert.Same(item1, view.Item),
view => Assert.Same(item3, view.Item));
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => applicationPartManager.PopulateFeature(feature));
Assert.Equal(expected, ex.Message);
}
[Fact]
@ -180,168 +123,58 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
{
// Arrange
var name = new AssemblyName($"DynamicAssembly-{Guid.NewGuid()}");
var assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect);
var assembly = AssemblyBuilder.DefineDynamicAssembly(name,
AssemblyBuilderAccess.RunAndCollect);
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(new AssemblyPart(assembly));
partManager.FeatureProviders.Add(new ViewsFeatureProvider());
var applicationPartManager = new ApplicationPartManager();
applicationPartManager.ApplicationParts.Add(new AssemblyPart(assembly));
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
applicationPartManager.PopulateFeature(feature);
// Assert
Assert.Empty(feature.ViewDescriptors);
}
[Fact]
public void PopulateFeature_ReadsAttributesFromTheCurrentAssembly()
{
// Arrange
var item1 = new RazorCompiledItemAttribute(typeof(string), "mvc.1.0.view", "view");
var assembly = new AssemblyWithEmptyLocation(
new RazorViewAttribute[] { new RazorViewAttribute("view", typeof(string)) },
new RazorCompiledItemAttribute[] { item1 });
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(new AssemblyPart(assembly));
partManager.FeatureProviders.Add(new ViewsFeatureProvider());
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
// Assert
var descriptor = Assert.Single(feature.ViewDescriptors);
Assert.Equal(typeof(string), descriptor.Item.Type);
Assert.Equal("mvc.1.0.view", descriptor.Item.Kind);
Assert.Equal("view", descriptor.Item.Identifier);
}
[Fact]
public void PopulateFeature_LegacyBehaviorDoesNotFail_IfAssemblyHasEmptyLocation()
public void PopulateFeature_DoesNotFail_IfAssemblyHasEmptyLocation()
{
// Arrange
var assembly = new AssemblyWithEmptyLocation();
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(new AssemblyPart(assembly));
partManager.FeatureProviders.Add(new OverrideViewsFeatureProvider());
var applicationPartManager = new ApplicationPartManager();
applicationPartManager.ApplicationParts.Add(new AssemblyPart(assembly));
applicationPartManager.FeatureProviders.Add(new ViewsFeatureProvider());
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
applicationPartManager.PopulateFeature(feature);
// Assert
Assert.Empty(feature.ViewDescriptors);
}
[Fact]
public void PopulateFeature_PreservesOldBehavior_IfGetViewAttributesWasOverriden()
{
// Arrange
var assembly = new AssemblyWithEmptyLocation(
new RazorViewAttribute[] { new RazorViewAttribute("view", typeof(string)) },
new RazorCompiledItemAttribute[] { });
var partManager = new ApplicationPartManager();
partManager.ApplicationParts.Add(new AssemblyPart(assembly));
partManager.FeatureProviders.Add(new OverrideViewsFeatureProvider());
var feature = new ViewsFeature();
// Act
partManager.PopulateFeature(feature);
// Assert
Assert.Empty(feature.ViewDescriptors);
}
internal class OverrideViewsFeatureProvider : ViewsFeatureProvider
{
protected override IEnumerable<RazorViewAttribute> GetViewAttributes(AssemblyPart assemblyPart)
=> base.GetViewAttributes(assemblyPart);
}
private class TestRazorCompiledItem : RazorCompiledItem
{
public TestRazorCompiledItem(Type type, string kind, string identifier, object[] metadata)
{
Type = type;
Kind = kind;
Identifier = identifier;
Metadata = metadata;
}
public override string Identifier { get; }
public override string Kind { get; }
public override IReadOnlyList<object> Metadata { get; }
public override Type Type { get; }
}
private class TestableViewsFeatureProvider : ViewsFeatureProvider
{
private readonly Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>> _attributes;
private readonly Dictionary<AssemblyPart, IReadOnlyList<RazorCompiledItem>> _items;
private readonly Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>> _attributeLookup;
public TestableViewsFeatureProvider(
Dictionary<AssemblyPart, IReadOnlyList<RazorCompiledItem>> items,
Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>> attributes)
public TestableViewsFeatureProvider(Dictionary<AssemblyPart, IEnumerable<RazorViewAttribute>> attributeLookup)
{
_items = items;
_attributes = attributes;
_attributeLookup = attributeLookup;
}
protected override IEnumerable<RazorViewAttribute> GetViewAttributes(AssemblyPart assemblyPart)
{
if (_attributes.TryGetValue(assemblyPart, out var attributes))
{
return attributes;
}
return Enumerable.Empty<RazorViewAttribute>();
}
internal override IReadOnlyList<RazorCompiledItem> LoadItems(AssemblyPart assemblyPart)
{
return _items[assemblyPart];
return _attributeLookup[assemblyPart];
}
}
private class AssemblyWithEmptyLocation : Assembly
{
private readonly RazorViewAttribute[] _razorViewAttributes;
private readonly RazorCompiledItemAttribute[] _razorCompiledItemAttributes;
public AssemblyWithEmptyLocation()
: this(Array.Empty<RazorViewAttribute>(), Array.Empty<RazorCompiledItemAttribute>())
{
}
public AssemblyWithEmptyLocation(
RazorViewAttribute[] razorViewAttributes,
RazorCompiledItemAttribute[] razorCompiledItemAttributes)
{
_razorViewAttributes = razorViewAttributes;
_razorCompiledItemAttributes = razorCompiledItemAttributes;
}
public override string Location => string.Empty;
public override string FullName => typeof(ViewsFeatureProviderTest).Assembly.FullName;
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
if (attributeType == typeof(RazorViewAttribute))
{
return _razorViewAttributes;
}
else
{
return _razorCompiledItemAttributes;
}
}
public override string FullName => typeof(ViewsFeatureProviderTest).GetTypeInfo().Assembly.FullName;
public override IEnumerable<TypeInfo> DefinedTypes
{
@ -360,4 +193,5 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
}
}
}
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@ -23,27 +23,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class RazorViewCompilerTest
{
[Fact]
public void Constructor_ThrowsIfMultiplePrecompiledViewsHavePathsDifferingOnlyInCase()
{
// Arrange
var fileProvider = new TestFileProvider();
var precompiledViews = new[]
{
new CompiledViewDescriptor { RelativePath = "/Views/Home/About.cshtml" },
new CompiledViewDescriptor { RelativePath = "/Views/home/About.cshtml" },
};
var message = string.Join(
Environment.NewLine,
"The following precompiled view paths differ only in case, which is not supported:",
precompiledViews[0].RelativePath,
precompiledViews[1].RelativePath);
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => GetViewCompiler(fileProvider, precompiledViews: precompiledViews));
Assert.Equal(message, ex.Message);
}
[Fact]
public async Task CompileAsync_ReturnsResultWithNullAttribute_IfFileIsNotFoundInFileSystem()
{

View File

@ -216,7 +216,10 @@ namespace Microsoft.AspNetCore.Mvc
feature => Assert.IsType<ViewComponentFeatureProvider>(feature),
feature => Assert.IsType<MetadataReferenceFeatureProvider>(feature),
feature => Assert.IsType<TagHelperFeatureProvider>(feature),
feature => Assert.IsType<RazorCompiledItemFeatureProvider>(feature),
#pragma warning disable CS0618 // Type or member is obsolete
feature => Assert.IsType<ViewsFeatureProvider>(feature));
#pragma warning restore CS0618 // Type or member is obsolete
}
[Fact]

View File

@ -0,0 +1,37 @@
#pragma checksum "D:\k\Mvc\test\WebSites\RazorBuildWebSite\Views\Common\CommonView.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "a09a0106df2e63aecf6fc6ddf30df39b489d9783"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/Views/Common/CommonView.cshtml", typeof(RazorBuildWebSite.Views.Precompilation._Views_Precompilation_CommonView))]
namespace RazorBuildWebSite.Views.Precompilation
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
public class _Views_Precompilation_CommonView : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
BeginContext(0, 48, true);
WriteLiteral("Hello from buildtime-compiled precompilation view!");
EndContext();
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,11 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Generated by the MSBuild WriteCodeFragment class.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ProvideApplicationPartFactoryAttribute("Microsoft.AspNetCore.Mvc.ApplicationParts.CompiledRazorAssemblyApplicationPartFac" +
"tory, Microsoft.AspNetCore.Mvc.Razor")]

View File

@ -0,0 +1,40 @@
#pragma checksum "D:\k\Mvc\test\WebSites\RazorBuildWebSite\Views\Common\CommonView.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "56260f24a80ae2b8854fd2c9a1005bae485882cc"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(RazorBuildWebSite.Views.Rzc.Views_Rzc_View), @"mvc.1.0.view", @"/Views/Common/CommonView.cshtml")]
[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/Views/CommonView.cshtml", typeof(RazorBuildWebSite.Views.Rzc.Views_Rzc_View))]
namespace RazorBuildWebSite.Views.Rzc
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"56260f24a80ae2b8854fd2c9a1005bae485882cc", @"/Views/Common/CommonView.cshtml")]
[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"f265f06036e4378eada2a78f5366ad0e13e1d8af", @"/_ViewImports.cshtml")]
internal class Views_Rzc_CommonView : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
BeginContext(0, 39, true);
WriteLiteral("Hello from buildtime-compiled rzc view!");
EndContext();
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc;
namespace RazorBuildWebSite.Controllers
{
public class CommonController : Controller
{
public new ActionResult View()
{
return base.View("CommonView");
}
}
}