// 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.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyModel; namespace Microsoft.AspNetCore.Mvc.Infrastructure { /// /// An that uses to discover assemblies that may /// contain Mvc specific types such as controllers, and view components. /// public class DefaultAssemblyProvider : IAssemblyProvider { private const string NativeImageSufix = ".ni"; private readonly Assembly _entryAssembly; private readonly DependencyContext _dependencyContext; /// /// Initializes a new instance of . /// /// The . public DefaultAssemblyProvider(IHostingEnvironment environment) : this( Assembly.Load(new AssemblyName(environment.ApplicationName)), DependencyContext.Load(Assembly.Load(new AssemblyName(environment.ApplicationName)))) { } // Internal for unit testing. internal DefaultAssemblyProvider(Assembly entryAssembly, DependencyContext dependencyContext) { _entryAssembly = entryAssembly; _dependencyContext = dependencyContext; } /// /// Gets the set of assembly names that are used as root for discovery of /// MVC controllers, view components and views. /// // DefaultControllerTypeProvider uses CandidateAssemblies to determine if the base type of a POCO controller // lives in an assembly that references MVC. CandidateAssemblies excludes all assemblies from the // ReferenceAssemblies set. Consequently adding WebApiCompatShim to this set would cause the ApiController to // fail this test. protected virtual HashSet ReferenceAssemblies { get; } = new HashSet(StringComparer.Ordinal) { "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.Host", "Microsoft.AspNetCore.Mvc.TagHelpers", "Microsoft.AspNetCore.Mvc.ViewFeatures" }; /// public IEnumerable CandidateAssemblies { get { if (_dependencyContext == null) { // Use the entry assembly as the sole candidate. return new[] { _entryAssembly }; } return GetCandidateLibraries() .SelectMany(library => library.RuntimeAssemblyGroups.GetDefaultGroup().AssetPaths) .Select(Load) .Where(assembly => assembly != null); } } /// /// Returns a list of libraries that references the assemblies in . /// By default it returns all assemblies that reference any of the primary MVC assemblies /// while ignoring MVC assemblies. /// /// A set of . // Internal for unit testing protected internal virtual IEnumerable GetCandidateLibraries() { if (ReferenceAssemblies == null) { return Enumerable.Empty(); } return _dependencyContext.RuntimeLibraries.Where(IsCandidateLibrary); } private static Assembly Load(string assetPath) { var name = Path.GetFileNameWithoutExtension(assetPath); if (name != null) { if (name.EndsWith(NativeImageSufix, StringComparison.OrdinalIgnoreCase)) { name = name.Substring(0, name.Length - NativeImageSufix.Length); } return Assembly.Load(new AssemblyName(name)); } return null; } private bool IsCandidateLibrary(RuntimeLibrary library) { Debug.Assert(ReferenceAssemblies != null); return library.Dependencies.Any(dependency => ReferenceAssemblies.Contains(dependency.Name)); } } }