diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultAssemblyProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultAssemblyProvider.cs
index 6a9da434fb..3681e8ef2a 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultAssemblyProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultAssemblyProvider.cs
@@ -25,9 +25,17 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
///
/// The .
public DefaultAssemblyProvider(IApplicationEnvironment environment)
+ : this(
+ Assembly.Load(new AssemblyName(environment.ApplicationName)),
+ DependencyContext.Load(Assembly.Load(new AssemblyName(environment.ApplicationName))))
{
- _entryAssembly = Assembly.Load(new AssemblyName(environment.ApplicationName));
- _dependencyContext = DependencyContext.Load(_entryAssembly);
+ }
+
+ // Internal for unit testing.
+ internal DefaultAssemblyProvider(Assembly entryAssembly, DependencyContext dependencyContext)
+ {
+ _entryAssembly = entryAssembly;
+ _dependencyContext = dependencyContext;
}
///
@@ -78,7 +86,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
/// while ignoring MVC assemblies.
///
/// A set of .
- protected virtual IEnumerable GetCandidateLibraries()
+ // Internal for unit testing
+ protected internal virtual IEnumerable GetCandidateLibraries()
{
if (ReferenceAssemblies == null)
{
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultAssemblyProviderTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultAssemblyProviderTests.cs
new file mode 100644
index 0000000000..eaf7fc37de
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultAssemblyProviderTests.cs
@@ -0,0 +1,220 @@
+// 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.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyModel;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Mvc.Infrastructure
+{
+ public class DefaultAssemblyProviderTests
+ {
+ private static readonly Assembly CurrentAssembly = typeof(DefaultAssemblyProviderTests).GetTypeInfo().Assembly;
+
+ [Fact]
+ public void GetCandidateLibraries_IgnoresMvcAssemblies()
+ {
+ // Arrange
+ var expected = GetLibrary("SomeRandomAssembly", "Microsoft.AspNetCore.Mvc.Abstractions");
+ var dependencyContext = new DependencyContext(
+ target: null,
+ runtime: null,
+ compilationOptions: CompilationOptions.Default,
+ compileLibraries: new CompilationLibrary[0],
+ runtimeLibraries: new[]
+ {
+ GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
+ GetLibrary("Microsoft.AspNetCore.Mvc"),
+ GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
+ expected,
+ });
+ var provider = new DefaultAssemblyProvider(CurrentAssembly, dependencyContext);
+
+ // Act
+ var candidates = provider.GetCandidateLibraries();
+
+ // Assert
+ Assert.Equal(new[] { expected }, candidates);
+ }
+
+ [Fact]
+ public void CandidateAssemblies_ReturnsEntryAssemblyIfDependencyContextIsNull()
+ {
+ // Arrange
+ var provider = new DefaultAssemblyProvider(CurrentAssembly, dependencyContext: null);
+
+ // Act
+ var candidates = provider.CandidateAssemblies;
+
+ // Assert
+ Assert.Equal(new[] { CurrentAssembly }, candidates);
+ }
+
+ [Fact]
+ public void GetCandidateLibraries_ReturnsLibrariesReferencingAnyMvcAssembly()
+ {
+ // Arrange
+ var dependencyContext = new DependencyContext(
+ target: null,
+ runtime: null,
+ compilationOptions: CompilationOptions.Default,
+ compileLibraries: new CompilationLibrary[0],
+ runtimeLibraries: 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"),
+ });
+ var provider = new DefaultAssemblyProvider(CurrentAssembly, dependencyContext);
+
+ // Act
+ var candidates = provider.GetCandidateLibraries();
+
+ // Assert
+ Assert.Equal(new[] { "Foo", "Bar", "Baz" }, candidates.Select(a => a.PackageName));
+ }
+
+ [Fact]
+ public void GetCandidateLibraries_ReturnsLibrariesReferencingOverriddenAssemblies()
+ {
+ // Arrange
+ var dependencyContext = new DependencyContext(
+ target: null,
+ runtime: null,
+ compilationOptions: CompilationOptions.Default,
+ compileLibraries: new CompilationLibrary[0],
+ runtimeLibraries: new[]
+ {
+ GetLibrary("Foo", "CustomMvc.Modules"),
+ GetLibrary("Bar", "CustomMvc.Application.Loader"),
+ GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
+ });
+ var referenceAssemblies = new HashSet
+ {
+ "CustomMvc.Modules",
+ "CustomMvc.Application.Loader"
+ };
+ var assemblyProvider = new OverridenAssemblyProvider(
+ CurrentAssembly,
+ dependencyContext,
+ referenceAssemblies);
+
+ // Act
+ var candidates = assemblyProvider.GetCandidateLibraries();
+
+ // Assert
+ Assert.Equal(new[] { "Foo", "Bar" }, candidates.Select(a => a.PackageName));
+ }
+
+ [Fact]
+ public void GetCandidateLibraries_ReturnsEmptySequenceWhenReferenceAssembliesIsNull()
+ {
+ // Arrange
+ var dependencyContext = new DependencyContext(
+ target: null,
+ runtime: null,
+ compilationOptions: CompilationOptions.Default,
+ compileLibraries: new CompilationLibrary[0],
+ runtimeLibraries: new[]
+ {
+ GetLibrary("Foo", "CustomMvc.Modules"),
+ GetLibrary("Bar", "CustomMvc.Application.Loader"),
+ GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
+ });
+ var assemblyProvider = new OverridenAssemblyProvider(
+ CurrentAssembly,
+ dependencyContext,
+ referenceAssemblies: null);
+
+ // Act
+ var candidates = assemblyProvider.GetCandidateLibraries();
+
+ // Assert
+ Assert.Empty(candidates);
+ }
+
+ // This test verifies DefaultAssemblyProvider.ReferenceAssemblies reflects the actual loadable assemblies
+ // of the libraries that Microsoft.AspNetCore.Mvc dependes on.
+ // If we add or remove dependencies, this test should be changed together.
+ [Fact]
+ public void ReferenceAssemblies_ReturnsLoadableReferenceAssemblies()
+ {
+ // Arrange
+ var provider = new TestableAssemblyProvider(CurrentAssembly, dependencyContext: null);
+ var excludeAssemblies = new string[]
+ {
+ "Microsoft.AspNetCore.Mvc.WebApiCompatShim",
+ "Microsoft.AspNetCore.Mvc.TestCommon",
+ "Microsoft.AspNetCore.Mvc.Core.Test",
+ "Microsoft.AspNetCore.Mvc.TestDiagnosticListener.Sources",
+ };
+
+ var additionalAssemblies = new[]
+ {
+ // The following assemblies are not reachable from Microsoft.AspNetCore.Mvc
+ "Microsoft.AspNetCore.Mvc.TagHelpers",
+ "Microsoft.AspNetCore.Mvc.Formatters.Xml",
+ };
+
+ var expected = DependencyContext.Load(CurrentAssembly)
+ .RuntimeLibraries
+ .Where(r => r.PackageName.StartsWith("Microsoft.AspNetCore.Mvc", StringComparison.Ordinal) &&
+ !excludeAssemblies.Contains(r.PackageName, StringComparer.OrdinalIgnoreCase))
+ .Select(r => r.PackageName)
+ .Concat(additionalAssemblies)
+ .Distinct()
+ .OrderBy(p => p, StringComparer.Ordinal);
+
+ // Act
+ var referenceAssemblies = provider.ReferenceAssemblies.OrderBy(p => p, StringComparer.Ordinal);
+
+ // Assert
+ Assert.Equal(expected, referenceAssemblies);
+ }
+
+ 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[] { $"{name}.dll" },
+ dependencies: dependencies.ToArray(),
+ serviceable: true);
+ }
+
+ private class OverridenAssemblyProvider : DefaultAssemblyProvider
+ {
+ public OverridenAssemblyProvider(
+ Assembly entryAssembly,
+ DependencyContext dependencyContext,
+ HashSet referenceAssemblies)
+ : base(entryAssembly, dependencyContext)
+ {
+ ReferenceAssemblies = referenceAssemblies;
+ }
+
+ protected override HashSet ReferenceAssemblies { get; }
+ }
+
+ private class TestableAssemblyProvider : DefaultAssemblyProvider
+ {
+ public TestableAssemblyProvider(
+ Assembly entryAssembly,
+ DependencyContext dependencyContext)
+ : base(entryAssembly, dependencyContext)
+ {
+ }
+
+ public new HashSet ReferenceAssemblies => base.ReferenceAssemblies;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/project.json b/test/Microsoft.AspNetCore.Mvc.Core.Test/project.json
index 2234554f99..79660823b8 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/project.json
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/project.json
@@ -1,7 +1,8 @@
{
"compilationOptions": {
"warningsAsErrors": true,
- "keyFile": "../../tools/Key.snk"
+ "keyFile": "../../tools/Key.snk",
+ "preserveCompilationContext": true
},
"dependencies": {
"Microsoft.AspNetCore.Http": "1.0.0-*",