Prevent StackOverflows when assemblies have recursive references (dotnet/aspnetcore-tooling#901)
* Prevent StackOverflows when assemblies have recursive references
https://github.com/aspnet/AspNetCore/issues/12693
\n\nCommit migrated from 43776c1864
This commit is contained in:
parent
7312e7cc38
commit
2699268bc3
|
|
@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
||||||
public bool IsSystemReference { get; set; }
|
public bool IsFrameworkReference { get; set; }
|
||||||
|
|
||||||
public string AssemblyName { get; set; }
|
public string AssemblyName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
referenceItems.Add(new AssemblyItem
|
referenceItems.Add(new AssemblyItem
|
||||||
{
|
{
|
||||||
AssemblyName = assemblyName,
|
AssemblyName = assemblyName,
|
||||||
IsSystemReference = item.GetMetadata("IsSystemReference") == "true",
|
IsFrameworkReference = item.GetMetadata("IsFrameworkReference") == "true",
|
||||||
Path = item.ItemSpec,
|
Path = item.ItemSpec,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection.Metadata;
|
using System.Reflection.Metadata;
|
||||||
using System.Reflection.PortableExecutable;
|
using System.Reflection.PortableExecutable;
|
||||||
|
|
||||||
|
|
@ -15,155 +17,141 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
public class ReferenceResolver
|
public class ReferenceResolver
|
||||||
{
|
{
|
||||||
private readonly HashSet<string> _mvcAssemblies;
|
private readonly HashSet<string> _mvcAssemblies;
|
||||||
private readonly Dictionary<string, ClassifiedAssemblyItem> _lookup = new Dictionary<string, ClassifiedAssemblyItem>(StringComparer.Ordinal);
|
private readonly IReadOnlyList<AssemblyItem> _assemblyItems;
|
||||||
|
private readonly Dictionary<AssemblyItem, Classification> _classifications;
|
||||||
|
|
||||||
public ReferenceResolver(IReadOnlyList<string> targetAssemblies, IReadOnlyList<AssemblyItem> assemblyItems)
|
public ReferenceResolver(IReadOnlyList<string> targetAssemblies, IReadOnlyList<AssemblyItem> assemblyItems)
|
||||||
{
|
{
|
||||||
_mvcAssemblies = new HashSet<string>(targetAssemblies, StringComparer.Ordinal);
|
_mvcAssemblies = new HashSet<string>(targetAssemblies, StringComparer.Ordinal);
|
||||||
|
_assemblyItems = assemblyItems;
|
||||||
|
_classifications = new Dictionary<AssemblyItem, Classification>();
|
||||||
|
|
||||||
|
Lookup = new Dictionary<string, AssemblyItem>(StringComparer.Ordinal);
|
||||||
foreach (var item in assemblyItems)
|
foreach (var item in assemblyItems)
|
||||||
{
|
{
|
||||||
var classifiedItem = new ClassifiedAssemblyItem(item);
|
Lookup[item.AssemblyName] = item;
|
||||||
_lookup[item.AssemblyName] = classifiedItem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Dictionary<string, AssemblyItem> Lookup { get; }
|
||||||
|
|
||||||
public IReadOnlyList<string> ResolveAssemblies()
|
public IReadOnlyList<string> ResolveAssemblies()
|
||||||
{
|
{
|
||||||
var applicationParts = new List<string>();
|
var applicationParts = new List<string>();
|
||||||
foreach (var item in _lookup)
|
|
||||||
{
|
|
||||||
var classification = Resolve(item.Value);
|
|
||||||
if (classification == DependencyClassification.ReferencesMvc)
|
|
||||||
{
|
|
||||||
applicationParts.Add(item.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's not interesting for us to know if a dependency has a classification of MvcReference.
|
foreach (var item in _assemblyItems)
|
||||||
// All applications targeting the Microsoft.AspNetCore.App will have have a reference to Mvc.
|
{
|
||||||
|
var classification = Resolve(item);
|
||||||
|
if (classification == Classification.ReferencesMvc)
|
||||||
|
{
|
||||||
|
applicationParts.Add(item.AssemblyName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return applicationParts;
|
return applicationParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DependencyClassification Resolve(ClassifiedAssemblyItem classifiedItem)
|
private Classification Resolve(AssemblyItem assemblyItem)
|
||||||
{
|
{
|
||||||
if (classifiedItem.DependencyClassification != DependencyClassification.Unknown)
|
if (_classifications.TryGetValue(assemblyItem, out var classification))
|
||||||
{
|
{
|
||||||
return classifiedItem.DependencyClassification;
|
return classification;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classifiedItem.AssemblyItem == null)
|
// Initialize the dictionary with a value to short-circuit recursive references.
|
||||||
|
classification = Classification.Unknown;
|
||||||
|
_classifications[assemblyItem] = classification;
|
||||||
|
|
||||||
|
if (assemblyItem.Path == null)
|
||||||
{
|
{
|
||||||
// We encountered a dependency that isn't part of this assembly's dependency set. We'll see if it happens to be an MVC assembly.
|
// We encountered a dependency that isn't part of this assembly's dependency set. We'll see if it happens to be an MVC assembly
|
||||||
// This might be useful in scenarios where the app does not have a framework reference at the entry point,
|
// since that's the only useful determination we can make given the assembly name.
|
||||||
// but the transitive dependency does.
|
classification = _mvcAssemblies.Contains(assemblyItem.AssemblyName) ?
|
||||||
classifiedItem.DependencyClassification = _mvcAssemblies.Contains(classifiedItem.Name) ?
|
Classification.IsMvc :
|
||||||
DependencyClassification.MvcReference :
|
Classification.DoesNotReferenceMvc;
|
||||||
DependencyClassification.DoesNotReferenceMvc;
|
|
||||||
|
|
||||||
return classifiedItem.DependencyClassification;
|
|
||||||
}
|
}
|
||||||
|
else if (assemblyItem.IsFrameworkReference)
|
||||||
if (classifiedItem.AssemblyItem.IsSystemReference)
|
|
||||||
{
|
{
|
||||||
// We do not allow transitive references to MVC via a framework reference to count.
|
// We do not allow transitive references to MVC via a framework reference to count.
|
||||||
// e.g. depending on Microsoft.AspNetCore.SomeThingNewThatDependsOnMvc would not result in an assembly being treated as
|
// e.g. depending on Microsoft.AspNetCore.SomeThingNewThatDependsOnMvc would not result in an assembly being treated as
|
||||||
// referencing MVC.
|
// referencing MVC.
|
||||||
classifiedItem.DependencyClassification = _mvcAssemblies.Contains(classifiedItem.Name) ?
|
classification = _mvcAssemblies.Contains(assemblyItem.AssemblyName) ?
|
||||||
DependencyClassification.MvcReference :
|
Classification.IsMvc :
|
||||||
DependencyClassification.DoesNotReferenceMvc;
|
Classification.DoesNotReferenceMvc;
|
||||||
|
|
||||||
return classifiedItem.DependencyClassification;
|
|
||||||
}
|
}
|
||||||
|
else if (_mvcAssemblies.Contains(assemblyItem.AssemblyName))
|
||||||
if (_mvcAssemblies.Contains(classifiedItem.Name))
|
|
||||||
{
|
{
|
||||||
classifiedItem.DependencyClassification = DependencyClassification.MvcReference;
|
classification = Classification.IsMvc;
|
||||||
return classifiedItem.DependencyClassification;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
var dependencyClassification = DependencyClassification.DoesNotReferenceMvc;
|
|
||||||
foreach (var assemblyItem in GetReferences(classifiedItem.AssemblyItem.Path))
|
|
||||||
{
|
{
|
||||||
var classification = Resolve(assemblyItem);
|
classification = Classification.DoesNotReferenceMvc;
|
||||||
if (classification == DependencyClassification.MvcReference || classification == DependencyClassification.ReferencesMvc)
|
foreach (var reference in GetReferences(assemblyItem.Path))
|
||||||
{
|
{
|
||||||
dependencyClassification = DependencyClassification.ReferencesMvc;
|
var referenceClassification = Resolve(reference);
|
||||||
break;
|
|
||||||
|
if (referenceClassification == Classification.IsMvc || referenceClassification == Classification.ReferencesMvc)
|
||||||
|
{
|
||||||
|
classification = Classification.ReferencesMvc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
classifiedItem.DependencyClassification = dependencyClassification;
|
Debug.Assert(classification != Classification.Unknown);
|
||||||
return dependencyClassification;
|
_classifications[assemblyItem] = classification;
|
||||||
|
return classification;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual IReadOnlyList<ClassifiedAssemblyItem> GetReferences(string file)
|
protected virtual IReadOnlyList<AssemblyItem> GetReferences(string file)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var peReader = new PEReader(File.OpenRead(file));
|
using var peReader = new PEReader(File.OpenRead(file));
|
||||||
if (!peReader.HasMetadata)
|
if (!peReader.HasMetadata)
|
||||||
{
|
{
|
||||||
return Array.Empty<ClassifiedAssemblyItem>(); // not a managed assembly
|
return Array.Empty<AssemblyItem>(); // not a managed assembly
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadataReader = peReader.GetMetadataReader();
|
var metadataReader = peReader.GetMetadataReader();
|
||||||
|
|
||||||
var assemblyItems = new List<ClassifiedAssemblyItem>();
|
var references = new List<AssemblyItem>();
|
||||||
foreach (var handle in metadataReader.AssemblyReferences)
|
foreach (var handle in metadataReader.AssemblyReferences)
|
||||||
{
|
{
|
||||||
var reference = metadataReader.GetAssemblyReference(handle);
|
var reference = metadataReader.GetAssemblyReference(handle);
|
||||||
var referenceName = metadataReader.GetString(reference.Name);
|
var referenceName = metadataReader.GetString(reference.Name);
|
||||||
|
|
||||||
if (_lookup.TryGetValue(referenceName, out var classifiedItem))
|
if (!Lookup.TryGetValue(referenceName, out var assemblyItem))
|
||||||
{
|
|
||||||
assemblyItems.Add(classifiedItem);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// A dependency references an item that isn't referenced by this project.
|
// A dependency references an item that isn't referenced by this project.
|
||||||
// We'll construct an item for so that we can calculate the classification based on it's name.
|
// We'll construct an item for so that we can calculate the classification based on it's name.
|
||||||
assemblyItems.Add(new ClassifiedAssemblyItem(referenceName));
|
assemblyItem = new AssemblyItem
|
||||||
|
{
|
||||||
|
AssemblyName = referenceName,
|
||||||
|
};
|
||||||
|
|
||||||
|
Lookup[referenceName] = assemblyItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
references.Add(assemblyItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return assemblyItems;
|
return references;
|
||||||
}
|
}
|
||||||
catch (BadImageFormatException)
|
catch (BadImageFormatException)
|
||||||
{
|
{
|
||||||
// not a PE file, or invalid metadata
|
// not a PE file, or invalid metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.Empty<ClassifiedAssemblyItem>(); // not a managed assembly
|
return Array.Empty<AssemblyItem>(); // not a managed assembly
|
||||||
}
|
}
|
||||||
|
|
||||||
protected enum DependencyClassification
|
protected enum Classification
|
||||||
{
|
{
|
||||||
Unknown,
|
Unknown,
|
||||||
DoesNotReferenceMvc,
|
DoesNotReferenceMvc,
|
||||||
ReferencesMvc,
|
ReferencesMvc,
|
||||||
MvcReference,
|
IsMvc,
|
||||||
}
|
|
||||||
|
|
||||||
protected class ClassifiedAssemblyItem
|
|
||||||
{
|
|
||||||
public ClassifiedAssemblyItem(AssemblyItem classifiedItem)
|
|
||||||
: this(classifiedItem.AssemblyName)
|
|
||||||
{
|
|
||||||
AssemblyItem = classifiedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClassifiedAssemblyItem(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
public AssemblyItem AssemblyItem { get; }
|
|
||||||
|
|
||||||
public DependencyClassification DependencyClassification { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,13 +59,13 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
var resolver = new TestReferencesToMvcResolver(new[]
|
var resolver = new TestReferencesToMvcResolver(new[]
|
||||||
{
|
{
|
||||||
CreateAssemblyItem("MyApp.Models"),
|
CreateAssemblyItem("MyApp.Models"),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.Mvc", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.Mvc", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.Hosting", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.Hosting", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.HttpAbstractions", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.HttpAbstractions", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.KestrelHttpServer", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.KestrelHttpServer", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.StaticFiles", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.StaticFiles", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.Extensions.Primitives", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.Extensions.Primitives", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("System.Net.Http", isSystemReference: true),
|
CreateAssemblyItem("System.Net.Http", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.EntityFrameworkCore"),
|
CreateAssemblyItem("Microsoft.EntityFrameworkCore"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -89,16 +89,16 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
// Arrange
|
// Arrange
|
||||||
var resolver = new TestReferencesToMvcResolver(new[]
|
var resolver = new TestReferencesToMvcResolver(new[]
|
||||||
{
|
{
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.Mvc", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.Mvc", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.Mvc.TagHelpers", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.Mvc.TagHelpers", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("MyTagHelpers"),
|
CreateAssemblyItem("MyTagHelpers"),
|
||||||
CreateAssemblyItem("MyControllers"),
|
CreateAssemblyItem("MyControllers"),
|
||||||
CreateAssemblyItem("MyApp.Models"),
|
CreateAssemblyItem("MyApp.Models"),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.Hosting", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.Hosting", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.HttpAbstractions", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.HttpAbstractions", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.KestrelHttpServer", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.KestrelHttpServer", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.StaticFiles", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.StaticFiles", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.Extensions.Primitives", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.Extensions.Primitives", isFrameworkReference: true),
|
||||||
CreateAssemblyItem("Microsoft.EntityFrameworkCore"),
|
CreateAssemblyItem("Microsoft.EntityFrameworkCore"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -126,13 +126,12 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
CreateAssemblyItem("MyCMS"),
|
CreateAssemblyItem("MyCMS"),
|
||||||
CreateAssemblyItem("MyCMS.Core"),
|
CreateAssemblyItem("MyCMS.Core"),
|
||||||
CreateAssemblyItem("Microsoft.AspNetCore.Mvc.ViewFeatures", isSystemReference: true),
|
CreateAssemblyItem("Microsoft.AspNetCore.Mvc.ViewFeatures", isFrameworkReference: true),
|
||||||
});
|
});
|
||||||
|
|
||||||
resolver.Add("MyCMS", "MyCMS.Core");
|
resolver.Add("MyCMS", "MyCMS.Core");
|
||||||
resolver.Add("MyCMS.Core", "Microsoft.AspNetCore.Mvc.ViewFeatures");
|
resolver.Add("MyCMS.Core", "Microsoft.AspNetCore.Mvc.ViewFeatures");
|
||||||
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var assemblies = resolver.ResolveAssemblies();
|
var assemblies = resolver.ResolveAssemblies();
|
||||||
|
|
||||||
|
|
@ -140,41 +139,93 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
Assert.Equal(new[] { "MyCMS", "MyCMS.Core" }, assemblies.OrderBy(a => a));
|
Assert.Equal(new[] { "MyCMS", "MyCMS.Core" }, assemblies.OrderBy(a => a));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssemblyItem CreateAssemblyItem(string name, bool isSystemReference = false)
|
[Fact]
|
||||||
|
public void Resolve_Works_WhenAssemblyReferencesAreRecursive()
|
||||||
|
{
|
||||||
|
// Test for https://github.com/aspnet/AspNetCore/issues/12693
|
||||||
|
// Arrange
|
||||||
|
var resolver = new TestReferencesToMvcResolver(new[]
|
||||||
|
{
|
||||||
|
CreateAssemblyItem("PresentationFramework"),
|
||||||
|
CreateAssemblyItem("ReachFramework"),
|
||||||
|
CreateAssemblyItem("MyCMS"),
|
||||||
|
CreateAssemblyItem("MyCMS.Core"),
|
||||||
|
CreateAssemblyItem("Microsoft.AspNetCore.Mvc.ViewFeatures", isFrameworkReference: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
resolver.Add("PresentationFramework", "ReachFramework");
|
||||||
|
resolver.Add("ReachFramework", "PresentationFramework");
|
||||||
|
|
||||||
|
resolver.Add("MyCMS", "MyCMS.Core");
|
||||||
|
resolver.Add("MyCMS.Core", "Microsoft.AspNetCore.Mvc.ViewFeatures");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var assemblies = resolver.ResolveAssemblies();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { "MyCMS", "MyCMS.Core" }, assemblies.OrderBy(a => a));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Resolve_Works_WhenAssemblyReferencesAreRecursive_ButAlsoReferencesMvc()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var resolver = new TestReferencesToMvcResolver(new[]
|
||||||
|
{
|
||||||
|
CreateAssemblyItem("MyCoolLibrary"),
|
||||||
|
CreateAssemblyItem("PresentationFramework"),
|
||||||
|
CreateAssemblyItem("ReachFramework"),
|
||||||
|
CreateAssemblyItem("MyCMS"),
|
||||||
|
CreateAssemblyItem("MyCMS.Core"),
|
||||||
|
CreateAssemblyItem("Microsoft.AspNetCore.Mvc.ViewFeatures", isFrameworkReference: true),
|
||||||
|
});
|
||||||
|
|
||||||
|
resolver.Add("MyCoolLibrary", "PresentationFramework");
|
||||||
|
resolver.Add("PresentationFramework", "ReachFramework");
|
||||||
|
resolver.Add("ReachFramework", "PresentationFramework", "MyCMS");
|
||||||
|
|
||||||
|
resolver.Add("MyCMS", "MyCMS.Core");
|
||||||
|
resolver.Add("MyCMS.Core", "Microsoft.AspNetCore.Mvc.ViewFeatures");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var assemblies = resolver.ResolveAssemblies();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { "MyCMS", "MyCMS.Core", "MyCoolLibrary", "PresentationFramework", "ReachFramework" }, assemblies.OrderBy(a => a));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssemblyItem CreateAssemblyItem(string name, bool isFrameworkReference = false)
|
||||||
{
|
{
|
||||||
return new AssemblyItem
|
return new AssemblyItem
|
||||||
{
|
{
|
||||||
AssemblyName = name,
|
AssemblyName = name,
|
||||||
IsSystemReference = isSystemReference,
|
IsFrameworkReference = isFrameworkReference,
|
||||||
Path = name,
|
Path = name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestReferencesToMvcResolver : ReferenceResolver
|
private class TestReferencesToMvcResolver : ReferenceResolver
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, List<ClassifiedAssemblyItem>> _references = new Dictionary<string, List<ClassifiedAssemblyItem>>();
|
private readonly Dictionary<string, string[]> _references = new Dictionary<string, string[]>();
|
||||||
private readonly Dictionary<string, ClassifiedAssemblyItem> _lookup;
|
|
||||||
|
|
||||||
public TestReferencesToMvcResolver(AssemblyItem[] referenceItems)
|
public TestReferencesToMvcResolver(AssemblyItem[] referenceItems)
|
||||||
: base(MvcAssemblies, referenceItems)
|
: base(MvcAssemblies, referenceItems)
|
||||||
{
|
{
|
||||||
_lookup = referenceItems.ToDictionary(r => r.AssemblyName, r => new ClassifiedAssemblyItem(r));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(string assembly, params string[] references)
|
public void Add(string assembly, params string[] references)
|
||||||
{
|
{
|
||||||
var assemblyItems = references.Select(r => _lookup[r]).ToList();
|
_references.Add(assembly, references);
|
||||||
_references[assembly] = assemblyItems;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IReadOnlyList<ClassifiedAssemblyItem> GetReferences(string file)
|
protected override IReadOnlyList<AssemblyItem> GetReferences(string file)
|
||||||
{
|
{
|
||||||
if (_references.TryGetValue(file, out var result))
|
if (_references.TryGetValue(file, out var result))
|
||||||
{
|
{
|
||||||
return result;
|
return result.Select(r => Lookup[r]).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.Empty<ClassifiedAssemblyItem>();
|
return Array.Empty<AssemblyItem>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue