坚持将一些 RC1 代码转换为 RC2
Stuck converting some RC1 code to RC2
在 RC1 中,我可以通过 Librarymanager
:
获得 Library
的程序集
_libraryManager.GetLibraries().SelectMany(l => l.Assemblies).Distinct().ToList();
在 RC2 中,似乎没有任何 API 可用于获取库的程序集。
我已阅读公告:https://github.com/aspnet/Announcements/issues/149并且该公告仅说明如何获取程序集的依赖项,并未说明如何获取库的程序集,现在程序集 属性 已弃用。
有人有什么想法吗?
我在这里也提出了一个 github 问题 https://github.com/aspnet/Home/issues/1554
您可以通过以下方式获取程序集:
libManager.GetLibraries()
.Where(x => x.Identity.Type == LibraryType.Project)
.Select(x => Assembly.Load(new AssemblyName(x.Identity.Name))).ToList();
这应该获取所有项目引用并加载程序集
从 RC1 到 RC2 的解决方案是放弃 ILibraryManager
并使用新的替代品 (DependencyContext)。在这里查看 MVC6 是如何做到的:
我也会在这里包含源代码,以防 link 由于某种原因消失:
// Discovers assemblies that are part of the MVC application using the DependencyContext.
public static class DefaultAssemblyPartDiscoveryProvider
{
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.Host",
"Microsoft.AspNetCore.Mvc.TagHelpers",
"Microsoft.AspNetCore.Mvc.ViewFeatures"
};
public static IEnumerable<ApplicationPart> DiscoverAssemblyParts(string entryPointAssemblyName)
{
var entryAssembly = Assembly.Load(new AssemblyName(entryPointAssemblyName));
var context = DependencyContext.Load(Assembly.Load(new AssemblyName(entryPointAssemblyName)));
return GetCandidateAssemblies(entryAssembly, context).Select(p => new AssemblyPart(p));
}
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> _dependencies;
public CandidateResolver(IReadOnlyList<RuntimeLibrary> dependencies, ISet<string> referenceAssemblies)
{
_dependencies = dependencies
.ToDictionary(d => d.Name, d => CreateDependency(d, referenceAssemblies), StringComparer.OrdinalIgnoreCase);
}
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)
{
Debug.Assert(_dependencies.ContainsKey(dependency));
var candidateEntry = _dependencies[dependency];
if (candidateEntry.Classification != DependencyClassification.Unknown)
{
return candidateEntry.Classification;
}
else
{
var classification = DependencyClassification.NotCandidate;
foreach (var candidateDependency in candidateEntry.Library.Dependencies)
{
var dependencyClassification = ComputeClassification(candidateDependency.Name);
if (dependencyClassification == DependencyClassification.Candidate ||
dependencyClassification == DependencyClassification.MvcReference)
{
classification = DependencyClassification.Candidate;
break;
}
}
candidateEntry.Classification = classification;
return classification;
}
}
public IEnumerable<RuntimeLibrary> GetCandidates()
{
foreach (var dependency in _dependencies)
{
if (ComputeClassification(dependency.Key) == DependencyClassification.Candidate)
{
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,
Candidate = 1,
NotCandidate = 2,
MvcReference = 3
}
}
}
在 RC1 中,我可以通过 Librarymanager
:
Library
的程序集
_libraryManager.GetLibraries().SelectMany(l => l.Assemblies).Distinct().ToList();
在 RC2 中,似乎没有任何 API 可用于获取库的程序集。
我已阅读公告:https://github.com/aspnet/Announcements/issues/149并且该公告仅说明如何获取程序集的依赖项,并未说明如何获取库的程序集,现在程序集 属性 已弃用。
有人有什么想法吗?
我在这里也提出了一个 github 问题 https://github.com/aspnet/Home/issues/1554
您可以通过以下方式获取程序集:
libManager.GetLibraries()
.Where(x => x.Identity.Type == LibraryType.Project)
.Select(x => Assembly.Load(new AssemblyName(x.Identity.Name))).ToList();
这应该获取所有项目引用并加载程序集
从 RC1 到 RC2 的解决方案是放弃 ILibraryManager
并使用新的替代品 (DependencyContext)。在这里查看 MVC6 是如何做到的:
我也会在这里包含源代码,以防 link 由于某种原因消失:
// Discovers assemblies that are part of the MVC application using the DependencyContext.
public static class DefaultAssemblyPartDiscoveryProvider
{
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.Host",
"Microsoft.AspNetCore.Mvc.TagHelpers",
"Microsoft.AspNetCore.Mvc.ViewFeatures"
};
public static IEnumerable<ApplicationPart> DiscoverAssemblyParts(string entryPointAssemblyName)
{
var entryAssembly = Assembly.Load(new AssemblyName(entryPointAssemblyName));
var context = DependencyContext.Load(Assembly.Load(new AssemblyName(entryPointAssemblyName)));
return GetCandidateAssemblies(entryAssembly, context).Select(p => new AssemblyPart(p));
}
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> _dependencies;
public CandidateResolver(IReadOnlyList<RuntimeLibrary> dependencies, ISet<string> referenceAssemblies)
{
_dependencies = dependencies
.ToDictionary(d => d.Name, d => CreateDependency(d, referenceAssemblies), StringComparer.OrdinalIgnoreCase);
}
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)
{
Debug.Assert(_dependencies.ContainsKey(dependency));
var candidateEntry = _dependencies[dependency];
if (candidateEntry.Classification != DependencyClassification.Unknown)
{
return candidateEntry.Classification;
}
else
{
var classification = DependencyClassification.NotCandidate;
foreach (var candidateDependency in candidateEntry.Library.Dependencies)
{
var dependencyClassification = ComputeClassification(candidateDependency.Name);
if (dependencyClassification == DependencyClassification.Candidate ||
dependencyClassification == DependencyClassification.MvcReference)
{
classification = DependencyClassification.Candidate;
break;
}
}
candidateEntry.Classification = classification;
return classification;
}
}
public IEnumerable<RuntimeLibrary> GetCandidates()
{
foreach (var dependency in _dependencies)
{
if (ComputeClassification(dependency.Key) == DependencyClassification.Candidate)
{
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,
Candidate = 1,
NotCandidate = 2,
MvcReference = 3
}
}
}