diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index dfb808fef..730fa9f63 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -12,6 +12,8 @@ namespace Microsoft.Extensions.DependencyModel { public class DependencyContextJsonReader : IDependencyContextReader { + private readonly IDictionary _stringPool = new Dictionary(); + public DependencyContext Read(Stream stream) { if (stream == null) @@ -28,6 +30,19 @@ namespace Microsoft.Extensions.DependencyModel } } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _stringPool.Clear(); + } + } + + public void Dispose() + { + Dispose(true); + } + private bool IsRuntimeTarget(string name) => name.Contains(DependencyContextStrings.VersionSeperator); private DependencyContext Read(JObject root) @@ -178,8 +193,8 @@ namespace Microsoft.Extensions.DependencyModel var seperatorPosition = nameWithVersion.IndexOf(DependencyContextStrings.VersionSeperator); - var name = nameWithVersion.Substring(0, seperatorPosition); - var version = nameWithVersion.Substring(seperatorPosition + 1); + var name = Pool(nameWithVersion.Substring(0, seperatorPosition)); + var version = Pool(nameWithVersion.Substring(seperatorPosition + 1)); var libraryObject = (JObject)property.Value; @@ -263,13 +278,13 @@ namespace Microsoft.Extensions.DependencyModel foreach (var resourceProperty in resourcesObject) { yield return new ResourceAssembly( - locale: resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value(), + locale: Pool(resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value()), path: resourceProperty.Key ); } } - private static IEnumerable ReadRuntimeTargetEntries(JObject runtimeTargetObject) + private IEnumerable ReadRuntimeTargetEntries(JObject runtimeTargetObject) { if (runtimeTargetObject == null) { @@ -281,8 +296,8 @@ namespace Microsoft.Extensions.DependencyModel yield return new RuntimeTargetEntryStub() { Path = libraryProperty.Key, - Rid = libraryObject[DependencyContextStrings.RidPropertyName].Value(), - Type = libraryObject[DependencyContextStrings.AssetTypePropertyName].Value() + Rid = Pool(libraryObject[DependencyContextStrings.RidPropertyName].Value()), + Type = Pool(libraryObject[DependencyContextStrings.AssetTypePropertyName].Value()) }; } } @@ -299,7 +314,7 @@ namespace Microsoft.Extensions.DependencyModel return assembliesObject.Properties().Select(property => property.Name).ToArray(); } - private static Dependency[] ReadDependencies(JObject libraryObject) + private Dependency[] ReadDependencies(JObject libraryObject) { var dependenciesObject = (JObject)libraryObject[DependencyContextStrings.DependenciesPropertyName]; @@ -309,7 +324,7 @@ namespace Microsoft.Extensions.DependencyModel } return dependenciesObject.Properties() - .Select(property => new Dependency(property.Name, (string)property.Value)).ToArray(); + .Select(property => new Dependency(Pool(property.Name), Pool((string)property.Value))).ToArray(); } private Dictionary ReadLibraryStubs(JObject librariesObject) @@ -322,9 +337,9 @@ namespace Microsoft.Extensions.DependencyModel var value = (JObject)libraryProperty.Value; var stub = new LibraryStub { - Name = libraryProperty.Key, + Name = Pool(libraryProperty.Key), Hash = value[DependencyContextStrings.Sha512PropertyName]?.Value(), - Type = value[DependencyContextStrings.TypePropertyName].Value(), + Type = Pool(value[DependencyContextStrings.TypePropertyName].Value()), Serviceable = value[DependencyContextStrings.ServiceablePropertyName]?.Value() == true }; libraries.Add(stub.Name, stub); @@ -333,6 +348,22 @@ namespace Microsoft.Extensions.DependencyModel return libraries; } + private string Pool(string s) + { + if (s == null) + { + return null; + } + + string result; + if (!_stringPool.TryGetValue(s, out result)) + { + _stringPool[s] = s; + result = s; + } + return result; + } + private struct RuntimeTargetEntryStub { public string Type; diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs index a1deb0fff..e7e4507f8 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs @@ -16,13 +16,13 @@ namespace Microsoft.Extensions.DependencyModel private readonly string _entryPointDepsLocation; private readonly string _runtimeDepsLocation; private readonly IFileSystem _fileSystem; - private readonly IDependencyContextReader _jsonReader; + private readonly Func _jsonReaderFactory; public DependencyContextLoader() : this( DependencyContextPaths.Current.Application, DependencyContextPaths.Current.SharedRuntime, FileSystemWrapper.Default, - new DependencyContextJsonReader()) + () => new DependencyContextJsonReader()) { } @@ -30,12 +30,12 @@ namespace Microsoft.Extensions.DependencyModel string entryPointDepsLocation, string runtimeDepsLocation, IFileSystem fileSystem, - IDependencyContextReader jsonReader) + Func jsonReaderFactory) { _entryPointDepsLocation = entryPointDepsLocation; _runtimeDepsLocation = runtimeDepsLocation; _fileSystem = fileSystem; - _jsonReader = jsonReader; + _jsonReaderFactory = jsonReaderFactory; } public static DependencyContextLoader Default { get; } = new DependencyContextLoader(); @@ -58,61 +58,63 @@ namespace Microsoft.Extensions.DependencyModel } DependencyContext context = null; - - if (IsEntryAssembly(assembly)) + using (var reader = _jsonReaderFactory()) { - context = LoadEntryAssemblyContext(); - } - - if (context == null) - { - context = LoadAssemblyContext(assembly); - } - - if (context?.Target.IsPortable == true) - { - var runtimeContext = LoadRuntimeContext(); - if (runtimeContext != null) + if (IsEntryAssembly(assembly)) { - context = context.Merge(runtimeContext); + context = LoadEntryAssemblyContext(reader); + } + + if (context == null) + { + context = LoadAssemblyContext(assembly, reader); + } + + if (context?.Target.IsPortable == true) + { + var runtimeContext = LoadRuntimeContext(reader); + if (runtimeContext != null) + { + context = context.Merge(runtimeContext); + } } } return context; } - private DependencyContext LoadEntryAssemblyContext() + private DependencyContext LoadEntryAssemblyContext(IDependencyContextReader reader) { if (!string.IsNullOrEmpty(_entryPointDepsLocation)) { Debug.Assert(File.Exists(_entryPointDepsLocation)); using (var stream = _fileSystem.File.OpenRead(_entryPointDepsLocation)) { - return _jsonReader.Read(stream); + return reader.Read(stream); } } return null; } - private DependencyContext LoadRuntimeContext() + private DependencyContext LoadRuntimeContext(IDependencyContextReader reader) { if (!string.IsNullOrEmpty(_runtimeDepsLocation)) { Debug.Assert(File.Exists(_runtimeDepsLocation)); using (var stream = _fileSystem.File.OpenRead(_runtimeDepsLocation)) { - return _jsonReader.Read(stream); + return reader.Read(stream); } } return null; } - private DependencyContext LoadAssemblyContext(Assembly assembly) + private DependencyContext LoadAssemblyContext(Assembly assembly, IDependencyContextReader reader) { using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension)) { if (stream != null) { - return _jsonReader.Read(stream); + return reader.Read(stream); } } @@ -121,7 +123,7 @@ namespace Microsoft.Extensions.DependencyModel { using (var stream = _fileSystem.File.OpenRead(depsJsonFile)) { - return _jsonReader.Read(stream); + return reader.Read(stream); } } diff --git a/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs b/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs index 57b2a442e..0603b5b66 100644 --- a/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs @@ -1,8 +1,9 @@ +using System; using System.IO; namespace Microsoft.Extensions.DependencyModel { - public interface IDependencyContextReader + public interface IDependencyContextReader: IDisposable { DependencyContext Read(Stream stream); }