Remove DependencyModel dependency

This commit is contained in:
Pranav K 2016-03-16 15:24:08 -07:00
parent cef81adb21
commit 4299a4d50b
30 changed files with 1908 additions and 649 deletions

View File

@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyModel.Resolution;
namespace Microsoft.Extensions.DependencyModel
{
internal class CompilationLibrary : Library
{
public CompilationLibrary(string type,
string name,
string version,
string hash,
IEnumerable<string> assemblies,
IEnumerable<Dependency> dependencies,
bool serviceable)
: base(type, name, version, hash, dependencies, serviceable)
{
Assemblies = assemblies.ToArray();
}
public IReadOnlyList<string> Assemblies { get; }
internal static ICompilationAssemblyResolver DefaultResolver { get; } = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[]
{
new PackageCacheCompilationAssemblyResolver(),
new AppBaseCompilationAssemblyResolver(),
new ReferenceAssemblyPathResolver(),
new PackageCompilationAssemblyResolver()
});
public IEnumerable<string> ResolveReferencePaths()
{
var assemblies = new List<string>();
if (!DefaultResolver.TryResolveAssemblyPaths(this, assemblies))
{
throw new InvalidOperationException($"Can not find compilation library location for package '{Name}'");
}
return assemblies;
}
}
}

View File

@ -0,0 +1,76 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class CompilationOptions
{
public IEnumerable<string> Defines { get; }
public string LanguageVersion { get; }
public string Platform { get; }
public bool? AllowUnsafe { get; }
public bool? WarningsAsErrors { get; }
public bool? Optimize { get; }
public string KeyFile { get; }
public bool? DelaySign { get; }
public bool? PublicSign { get; }
public string DebugType { get; }
public bool? EmitEntryPoint { get; }
public bool? GenerateXmlDocumentation { get; }
public static CompilationOptions Default { get; } = new CompilationOptions(
defines: Enumerable.Empty<string>(),
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: null,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
public CompilationOptions(IEnumerable<string> defines,
string languageVersion,
string platform,
bool? allowUnsafe,
bool? warningsAsErrors,
bool? optimize,
string keyFile,
bool? delaySign,
bool? publicSign,
string debugType,
bool? emitEntryPoint,
bool? generateXmlDocumentation)
{
Defines = defines;
LanguageVersion = languageVersion;
Platform = platform;
AllowUnsafe = allowUnsafe;
WarningsAsErrors = warningsAsErrors;
Optimize = optimize;
KeyFile = keyFile;
DelaySign = delaySign;
PublicSign = publicSign;
DebugType = debugType;
EmitEntryPoint = emitEntryPoint;
GenerateXmlDocumentation = generateXmlDocumentation;
}
}
}

View File

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Extensions.Internal;
namespace Microsoft.Extensions.DependencyModel
{
internal struct Dependency
{
public Dependency(string name, string version)
{
Name = name;
Version = version;
}
public string Name { get; }
public string Version { get; }
public bool Equals(Dependency other)
{
return string.Equals(Name, other.Name) && string.Equals(Version, other.Version);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is Dependency && Equals((Dependency) obj);
}
public override int GetHashCode()
{
var combiner = HashCodeCombiner.Start();
combiner.Add(Name);
combiner.Add(Version);
return combiner.CombinedHash;
}
}
}

View File

@ -0,0 +1,115 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class DependencyContext
{
private static readonly Lazy<DependencyContext> _defaultContext = new Lazy<DependencyContext>(LoadDefault);
public DependencyContext(string targetFramework,
string runtime,
bool isPortable,
CompilationOptions compilationOptions,
IEnumerable<CompilationLibrary> compileLibraries,
IEnumerable<RuntimeLibrary> runtimeLibraries,
IEnumerable<RuntimeFallbacks> runtimeGraph)
{
if (targetFramework == null)
{
throw new ArgumentNullException(nameof(targetFramework));
}
if (runtime == null)
{
throw new ArgumentNullException(nameof(runtime));
}
if (compilationOptions == null)
{
throw new ArgumentNullException(nameof(compilationOptions));
}
if (compileLibraries == null)
{
throw new ArgumentNullException(nameof(compileLibraries));
}
if (runtimeLibraries == null)
{
throw new ArgumentNullException(nameof(runtimeLibraries));
}
if (runtimeGraph == null)
{
throw new ArgumentNullException(nameof(runtimeGraph));
}
TargetFramework = targetFramework;
Runtime = runtime;
IsPortable = isPortable;
CompilationOptions = compilationOptions;
CompileLibraries = compileLibraries.ToArray();
RuntimeLibraries = runtimeLibraries.ToArray();
RuntimeGraph = runtimeGraph.ToArray();
}
public static DependencyContext Default => _defaultContext.Value;
public string TargetFramework { get; }
public string Runtime { get; }
public bool IsPortable { get; }
public CompilationOptions CompilationOptions { get; }
public IReadOnlyList<CompilationLibrary> CompileLibraries { get; }
public IReadOnlyList<RuntimeLibrary> RuntimeLibraries { get; }
public IReadOnlyList<RuntimeFallbacks> RuntimeGraph { get; }
public DependencyContext Merge(DependencyContext other)
{
if (other == null)
{
throw new ArgumentNullException(nameof(other));
}
return new DependencyContext(
TargetFramework,
Runtime,
IsPortable,
CompilationOptions,
CompileLibraries.Union(other.CompileLibraries, new LibraryMergeEqualityComparer<CompilationLibrary>()),
RuntimeLibraries.Union(other.RuntimeLibraries, new LibraryMergeEqualityComparer<RuntimeLibrary>()),
RuntimeGraph.Union(other.RuntimeGraph)
);
}
private static DependencyContext LoadDefault()
{
return DependencyContextLoader.Default.Load(Assembly.GetEntryAssembly());
}
public static DependencyContext Load(Assembly assembly)
{
return DependencyContextLoader.Default.Load(assembly);
}
private class LibraryMergeEqualityComparer<T>: IEqualityComparer<T> where T:Library
{
public bool Equals(T x, T y)
{
return string.Equals(x.Name, y.Name, StringComparison.Ordinal);
}
public int GetHashCode(T obj)
{
return obj.Name.GetHashCode();
}
}
}
}

View File

@ -0,0 +1,135 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Microsoft.Extensions.DependencyModel
{
internal class DependencyContextCsvReader: IDependencyContextReader
{
public DependencyContext Read(Stream stream)
{
var lines = new List<DepsFileLine>();
using (var reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
var line = new DepsFileLine();
line.LibraryType = ReadValue(reader);
line.PackageName = ReadValue(reader);
line.PackageVersion = ReadValue(reader);
line.PackageHash = ReadValue(reader);
line.AssetType = ReadValue(reader);
line.AssetName = ReadValue(reader);
line.AssetPath = ReadValue(reader);
if (line.AssetType == "runtime" &&
!line.AssetPath.EndsWith(".ni.dll"))
{
lines.Add(line);
}
SkipWhitespace(reader);
}
}
var runtimeLibraries = new List<RuntimeLibrary>();
var packageGroups = lines.GroupBy(PackageIdentity);
foreach (var packageGroup in packageGroups)
{
var identity = packageGroup.Key;
runtimeLibraries.Add(new RuntimeLibrary(
type: identity.Item1,
name: identity.Item2,
version: identity.Item3,
hash: identity.Item4,
assemblies: packageGroup.Select(l => RuntimeAssembly.Create(l.AssetPath)),
nativeLibraries: Enumerable.Empty<string>(),
resourceAssemblies: Enumerable.Empty<ResourceAssembly>(),
subTargets: Enumerable.Empty<RuntimeTarget>(),
dependencies: Enumerable.Empty<Dependency>(),
serviceable: false
));
}
return new DependencyContext(
targetFramework: string.Empty,
runtime: string.Empty,
isPortable: false,
compilationOptions: CompilationOptions.Default,
compileLibraries: Enumerable.Empty<CompilationLibrary>(),
runtimeLibraries: runtimeLibraries.ToArray(),
runtimeGraph: Enumerable.Empty<RuntimeFallbacks>());
}
private Tuple<string, string, string, string> PackageIdentity(DepsFileLine line)
{
return Tuple.Create(line.LibraryType, line.PackageName, line.PackageVersion, line.PackageHash);
}
private void SkipWhitespace(StreamReader reader)
{
// skip all whitespace
while (!reader.EndOfStream && char.IsWhiteSpace((char)reader.Peek()))
{
reader.Read();
}
}
private string ReadValue(StreamReader reader)
{
SkipWhitespace(reader);
var c = ReadSucceed(reader.Read());
if (c != '"')
{
throw new FormatException("Deps file value should start with '\"'");
}
var value = new StringBuilder();
while (ReadSucceed(reader.Peek()) != '"')
{
c = ReadSucceed(reader.Read());
if (c == '\\')
{
value.Append(ReadSucceed(reader.Read()));
}
else
{
value.Append(c);
}
}
// Read last "
ReadSucceed(reader.Read());
// Read comment
if (reader.Peek() == ',')
{
reader.Read();
}
return value.ToString();
}
private char ReadSucceed(int c)
{
if (c == -1)
{
throw new FormatException("Unexpected end of file");
}
return (char) c;
}
private struct DepsFileLine
{
public string LibraryType;
public string PackageName;
public string PackageVersion;
public string PackageHash;
public string AssetType;
public string AssetName;
public string AssetPath;
}
}
}

View File

@ -0,0 +1,294 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class DependencyContextJsonReader: IDependencyContextReader
{
public DependencyContext Read(Stream stream)
{
using (var streamReader = new StreamReader(stream))
{
using (var reader = new JsonTextReader(streamReader))
{
var root = JObject.Load(reader);
return Read(root);
}
}
}
private bool IsRuntimeTarget(string name) => name.Contains(DependencyContextStrings.VersionSeperator);
private DependencyContext Read(JObject root)
{
var runtime = string.Empty;
var target = string.Empty;
var isPortable = true;
var runtimeTargetName = root[DependencyContextStrings.RuntimeTargetPropertyName]?.Value<string>();
var libraryStubs = ReadLibraryStubs((JObject) root[DependencyContextStrings.LibrariesPropertyName]);
var targetsObject = (JObject) root[DependencyContextStrings.TargetsPropertyName];
JObject runtimeTarget = null;
JObject compileTarget = null;
if (targetsObject != null)
{
var compileTargetProperty = targetsObject.Properties()
.FirstOrDefault(p => !IsRuntimeTarget(p.Name));
compileTarget = (JObject)compileTargetProperty.Value;
target = compileTargetProperty.Name;
if (!string.IsNullOrEmpty(runtimeTargetName))
{
runtimeTarget = (JObject) targetsObject[runtimeTargetName];
if (runtimeTarget == null)
{
throw new FormatException($"Target with name {runtimeTargetName} not found");
}
var seperatorIndex = runtimeTargetName.IndexOf(DependencyContextStrings.VersionSeperator);
if (seperatorIndex > -1 && seperatorIndex < runtimeTargetName.Length)
{
runtime = runtimeTargetName.Substring(seperatorIndex + 1);
isPortable = false;
}
}
else
{
runtimeTarget = compileTarget;
}
}
return new DependencyContext(
target,
runtime,
isPortable,
ReadCompilationOptions((JObject)root[DependencyContextStrings.CompilationOptionsPropertName]),
ReadLibraries(compileTarget, false, libraryStubs).Cast<CompilationLibrary>().ToArray(),
ReadLibraries(runtimeTarget, true, libraryStubs).Cast<RuntimeLibrary>().ToArray(),
ReadRuntimeGraph((JObject)root[DependencyContextStrings.RuntimesPropertyName]).ToArray()
);
}
private IEnumerable<RuntimeFallbacks> ReadRuntimeGraph(JObject runtimes)
{
if (runtimes == null)
{
yield break;
}
foreach (var pair in runtimes)
{
yield return new RuntimeFallbacks(pair.Key, pair.Value.Values<string>().ToArray());
}
}
private CompilationOptions ReadCompilationOptions(JObject compilationOptionsObject)
{
if (compilationOptionsObject == null)
{
return CompilationOptions.Default;
}
return new CompilationOptions(
compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values<string>(),
compilationOptionsObject[DependencyContextStrings.LanguageVersionPropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.PlatformPropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.AllowUnsafePropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.WarningsAsErrorsPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.OptimizePropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.KeyFilePropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.DelaySignPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.PublicSignPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.DebugTypePropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.EmitEntryPointPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.GenerateXmlDocumentationPropertyName]?.Value<bool>()
);
}
private IEnumerable<Library> ReadLibraries(JObject librariesObject, bool runtime, Dictionary<string, LibraryStub> libraryStubs)
{
if (librariesObject == null)
{
return Enumerable.Empty<Library>();
}
return librariesObject.Properties().Select(property => ReadLibrary(property, runtime, libraryStubs));
}
private Library ReadLibrary(JProperty property, bool runtime, Dictionary<string, LibraryStub> libraryStubs)
{
var nameWithVersion = property.Name;
LibraryStub stub;
if (!libraryStubs.TryGetValue(nameWithVersion, out stub))
{
throw new InvalidOperationException($"Cannot find library information for {nameWithVersion}");
}
var seperatorPosition = nameWithVersion.IndexOf(DependencyContextStrings.VersionSeperator);
var name = nameWithVersion.Substring(0, seperatorPosition);
var version = nameWithVersion.Substring(seperatorPosition + 1);
var libraryObject = (JObject) property.Value;
var dependencies = ReadDependencies(libraryObject);
if (runtime)
{
var runtimeTargets = new List<RuntimeTarget>();
var runtimeTargetsObject = (JObject)libraryObject[DependencyContextStrings.RuntimeTargetsPropertyName];
var entries = ReadRuntimeTargetEntries(runtimeTargetsObject).ToArray();
foreach (var ridGroup in entries.GroupBy(e => e.Rid))
{
var runtimeAssets = entries.Where(e => e.Type == DependencyContextStrings.RuntimeAssetType)
.Select(e => RuntimeAssembly.Create(e.Path))
.ToArray();
var nativeAssets = entries.Where(e => e.Type == DependencyContextStrings.NativeAssetType)
.Select(e => e.Path)
.ToArray();
runtimeTargets.Add(new RuntimeTarget(
ridGroup.Key,
runtimeAssets,
nativeAssets
));
}
var assemblies = ReadAssetList(libraryObject, DependencyContextStrings.RuntimeAssembliesKey)
.Select(RuntimeAssembly.Create)
.ToArray();
var nativeLibraries = ReadAssetList(libraryObject, DependencyContextStrings.NativeLibrariesKey);
var resourceAssemblies = ReadResourceAssemblies((JObject)libraryObject[DependencyContextStrings.ResourceAssembliesPropertyName]);
return new RuntimeLibrary(
type: stub.Type,
name: name,
version: version,
hash: stub.Hash,
assemblies: assemblies,
nativeLibraries: nativeLibraries,
resourceAssemblies: resourceAssemblies,
subTargets: runtimeTargets.ToArray(),
dependencies: dependencies,
serviceable: stub.Serviceable);
}
else
{
var assemblies = ReadAssetList(libraryObject, DependencyContextStrings.CompileTimeAssembliesKey);
return new CompilationLibrary(stub.Type, name, version, stub.Hash, assemblies, dependencies, stub.Serviceable);
}
}
private IEnumerable<ResourceAssembly> ReadResourceAssemblies(JObject resourcesObject)
{
if (resourcesObject == null)
{
yield break;
}
foreach (var resourceProperty in resourcesObject)
{
yield return new ResourceAssembly(
locale: resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value<string>(),
path: resourceProperty.Key
);
}
}
private static IEnumerable<RuntimeTargetEntryStub> ReadRuntimeTargetEntries(JObject runtimeTargetObject)
{
if (runtimeTargetObject == null)
{
yield break;
}
foreach (var libraryProperty in runtimeTargetObject)
{
var libraryObject = (JObject)libraryProperty.Value;
yield return new RuntimeTargetEntryStub()
{
Path = libraryProperty.Key,
Rid = libraryObject[DependencyContextStrings.RidPropertyName].Value<string>(),
Type = libraryObject[DependencyContextStrings.AssetTypePropertyName].Value<string>()
};
}
}
private static string[] ReadAssetList(JObject libraryObject, string name)
{
var assembliesObject = (JObject) libraryObject[name];
if (assembliesObject == null)
{
return new string[] {};
}
return assembliesObject.Properties().Select(property => property.Name).ToArray();
}
private static Dependency[] ReadDependencies(JObject libraryObject)
{
var dependenciesObject = (JObject) libraryObject[DependencyContextStrings.DependenciesPropertyName];
if (dependenciesObject == null)
{
return new Dependency[]{ };
}
return dependenciesObject.Properties()
.Select(property => new Dependency(property.Name, (string) property.Value)).ToArray();
}
private Dictionary<string, LibraryStub> ReadLibraryStubs(JObject librariesObject)
{
var libraries = new Dictionary<string, LibraryStub>();
if (librariesObject != null)
{
foreach (var libraryProperty in librariesObject)
{
var value = (JObject) libraryProperty.Value;
var stub = new LibraryStub
{
Name = libraryProperty.Key,
Hash = value[DependencyContextStrings.Sha512PropertyName]?.Value<string>(),
Type = value[DependencyContextStrings.TypePropertyName].Value<string>(),
Serviceable = value[DependencyContextStrings.ServiceablePropertyName]?.Value<bool>() == true
};
libraries.Add(stub.Name, stub);
}
}
return libraries;
}
private struct RuntimeTargetEntryStub
{
public string Type;
public string Path;
public string Rid;
}
private struct LibraryStub
{
public string Name;
public string Hash;
public string Type;
public bool Serviceable;
}
}
}

View File

@ -0,0 +1,170 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
namespace Microsoft.Extensions.DependencyModel
{
internal class DependencyContextLoader
{
private static Lazy<string[]> _depsFiles = new Lazy<string[]>(GetHostDepsList);
private const string DepsJsonExtension = ".deps.json";
private const string DepsExtension = ".deps";
private readonly string _entryPointDepsLocation;
private readonly string _runtimeDepsLocation;
private readonly IDependencyContextReader _jsonReader;
private readonly IDependencyContextReader _csvReader;
public DependencyContextLoader() : this(
GetDefaultEntrypointDepsLocation(),
GetDefaultRuntimeDepsLocation(),
new DependencyContextJsonReader(),
new DependencyContextCsvReader())
{
}
internal DependencyContextLoader(
string entryPointDepsLocation,
string runtimeDepsLocation,
IDependencyContextReader jsonReader,
IDependencyContextReader csvReader)
{
_entryPointDepsLocation = entryPointDepsLocation;
_runtimeDepsLocation = runtimeDepsLocation;
_jsonReader = jsonReader;
_csvReader = csvReader;
}
public static DependencyContextLoader Default { get; } = new DependencyContextLoader();
internal virtual bool IsEntryAssembly(Assembly assembly)
{
return assembly.GetName() == Assembly.GetEntryAssembly()?.GetName();
}
internal virtual Stream GetResourceStream(Assembly assembly, string name)
{
return assembly.GetManifestResourceStream(name);
}
public DependencyContext Load(Assembly assembly)
{
if (assembly == null)
{
throw new ArgumentNullException(nameof(assembly));
}
DependencyContext context = null;
if (IsEntryAssembly(assembly))
{
context = LoadEntryAssemblyContext();
}
if (context == null)
{
context = LoadAssemblyContext(assembly);
}
if (context?.IsPortable == true)
{
var runtimeContext = LoadRuntimeContext();
if (runtimeContext != null)
{
context = context.Merge(runtimeContext);
}
}
return context;
}
private DependencyContext LoadEntryAssemblyContext()
{
if (!string.IsNullOrEmpty(_entryPointDepsLocation))
{
Debug.Assert(File.Exists(_entryPointDepsLocation));
using (var stream = File.OpenRead(_entryPointDepsLocation))
{
return _jsonReader.Read(stream);
}
}
return null;
}
private DependencyContext LoadRuntimeContext()
{
if (!string.IsNullOrEmpty(_runtimeDepsLocation))
{
Debug.Assert(File.Exists(_runtimeDepsLocation));
using (var stream = File.OpenRead(_runtimeDepsLocation))
{
return _jsonReader.Read(stream);
}
}
return null;
}
private DependencyContext LoadAssemblyContext(Assembly assembly)
{
using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension))
{
if (stream != null)
{
return _jsonReader.Read(stream);
}
}
var depsJsonFile = Path.ChangeExtension(assembly.Location, DepsJsonExtension);
if (File.Exists(depsJsonFile))
{
using (var stream = File.OpenRead(depsJsonFile))
{
return _jsonReader.Read(stream);
}
}
var depsFile = Path.ChangeExtension(assembly.Location, DepsExtension);
if (File.Exists(depsFile))
{
using (var stream = File.OpenRead(depsFile))
{
return _csvReader.Read(stream);
}
}
return null;
}
private static string GetDefaultRuntimeDepsLocation()
{
var deps = _depsFiles.Value;
if (deps != null && deps.Length > 1)
{
return deps[1];
}
return null;
}
private static string GetDefaultEntrypointDepsLocation()
{
var deps = _depsFiles.Value;
if (deps != null && deps.Length > 0)
{
return deps[0];
}
return null;
}
private static string[] GetHostDepsList()
{
// TODO: Were going to replace this with AppContext.GetData
var appDomainType = typeof(object).GetTypeInfo().Assembly?.GetType("System.AppDomain");
var currentDomain = appDomainType?.GetProperty("CurrentDomain")?.GetValue(null);
var deps = appDomainType?.GetMethod("GetData")?.Invoke(currentDomain, new[] { "APP_CONTEXT_DEPS_FILES" });
return (deps as string)?.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries);
}
}
}

View File

@ -0,0 +1,76 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.Extensions.DependencyModel
{
internal class DependencyContextStrings
{
internal const char VersionSeperator = '/';
internal const string CompileTimeAssembliesKey = "compile";
internal const string RuntimeAssembliesKey = "runtime";
internal const string NativeLibrariesKey = "native";
internal const string RuntimeTargetPropertyName = "runtimeTarget";
internal const string LibrariesPropertyName = "libraries";
internal const string TargetsPropertyName = "targets";
internal const string DependenciesPropertyName = "dependencies";
internal const string Sha512PropertyName = "sha512";
internal const string TypePropertyName = "type";
internal const string ServiceablePropertyName = "serviceable";
internal const string CompilationOptionsPropertName = "compilationOptions";
internal const string DefinesPropertyName = "defines";
internal const string LanguageVersionPropertyName = "languageVersion";
internal const string PlatformPropertyName = "platform";
internal const string AllowUnsafePropertyName = "allowUnsafe";
internal const string WarningsAsErrorsPropertyName = "warningsAsErrors";
internal const string OptimizePropertyName = "optimize";
internal const string KeyFilePropertyName = "keyFile";
internal const string DelaySignPropertyName = "delaySign";
internal const string PublicSignPropertyName = "publicSign";
internal const string DebugTypePropertyName = "debugType";
internal const string EmitEntryPointPropertyName = "emitEntryPoint";
internal const string GenerateXmlDocumentationPropertyName = "xmlDoc";
internal const string PortablePropertyName = "portable";
internal const string RuntimeTargetNamePropertyName = "name";
internal const string RuntimesPropertyName = "runtimes";
internal const string RuntimeTargetsPropertyName = "runtimeTargets";
internal const string RidPropertyName = "rid";
internal const string AssetTypePropertyName = "assetType";
internal const string RuntimeAssetType = "runtime";
internal const string NativeAssetType = "native";
internal const string ResourceAssembliesPropertyName = "resources";
internal const string LocalePropertyName = "locale";
}
}

View File

@ -0,0 +1,309 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Extensions.PlatformAbstractions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class DependencyContextWriter
{
public void Write(DependencyContext context, Stream stream)
{
using (var writer = new StreamWriter(stream))
{
using (var jsonWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented })
{
Write(context).WriteTo(jsonWriter);
}
}
}
private JObject Write(DependencyContext context)
{
var contextObject = new JObject(
new JProperty(DependencyContextStrings.RuntimeTargetPropertyName, WriteRuntimeTargetInfo(context)),
new JProperty(DependencyContextStrings.CompilationOptionsPropertName, WriteCompilationOptions(context.CompilationOptions)),
new JProperty(DependencyContextStrings.TargetsPropertyName, WriteTargets(context)),
new JProperty(DependencyContextStrings.LibrariesPropertyName, WriteLibraries(context))
);
if (context.RuntimeGraph.Any())
{
contextObject.Add(new JProperty(DependencyContextStrings.RuntimesPropertyName, WriteRuntimeGraph(context)));
}
return contextObject;
}
private string WriteRuntimeTargetInfo(DependencyContext context)
{
return context.IsPortable?
context.TargetFramework :
context.TargetFramework + DependencyContextStrings.VersionSeperator + context.Runtime;
}
private JObject WriteRuntimeGraph(DependencyContext context)
{
return new JObject(
context.RuntimeGraph.Select(g => new JProperty(g.Runtime, new JArray(g.Fallbacks)))
);
}
private JObject WriteCompilationOptions(CompilationOptions compilationOptions)
{
var o = new JObject();
if (compilationOptions.Defines?.Any() == true)
{
o[DependencyContextStrings.DefinesPropertyName] = new JArray(compilationOptions.Defines);
}
AddPropertyIfNotNull(o, DependencyContextStrings.LanguageVersionPropertyName, compilationOptions.LanguageVersion);
AddPropertyIfNotNull(o, DependencyContextStrings.PlatformPropertyName, compilationOptions.Platform);
AddPropertyIfNotNull(o, DependencyContextStrings.AllowUnsafePropertyName, compilationOptions.AllowUnsafe);
AddPropertyIfNotNull(o, DependencyContextStrings.WarningsAsErrorsPropertyName, compilationOptions.WarningsAsErrors);
AddPropertyIfNotNull(o, DependencyContextStrings.OptimizePropertyName, compilationOptions.Optimize);
AddPropertyIfNotNull(o, DependencyContextStrings.KeyFilePropertyName, compilationOptions.KeyFile);
AddPropertyIfNotNull(o, DependencyContextStrings.DelaySignPropertyName, compilationOptions.DelaySign);
AddPropertyIfNotNull(o, DependencyContextStrings.PublicSignPropertyName, compilationOptions.PublicSign);
AddPropertyIfNotNull(o, DependencyContextStrings.EmitEntryPointPropertyName, compilationOptions.EmitEntryPoint);
AddPropertyIfNotNull(o, DependencyContextStrings.GenerateXmlDocumentationPropertyName, compilationOptions.GenerateXmlDocumentation);
AddPropertyIfNotNull(o, DependencyContextStrings.DebugTypePropertyName, compilationOptions.DebugType);
return o;
}
private void AddPropertyIfNotNull<T>(JObject o, string name, T value)
{
if (value != null)
{
o.Add(new JProperty(name, value));
}
}
private JObject WriteTargets(DependencyContext context)
{
if (context.IsPortable)
{
return new JObject(
new JProperty(context.TargetFramework, WritePortableTarget(context.RuntimeLibraries, context.CompileLibraries))
);
}
return new JObject(
new JProperty(context.TargetFramework, WriteTarget(context.CompileLibraries)),
new JProperty(context.TargetFramework + DependencyContextStrings.VersionSeperator + context.Runtime,
WriteTarget(context.RuntimeLibraries))
);
}
private JObject WriteTarget(IReadOnlyList<Library> libraries)
{
return new JObject(
libraries.Select(library =>
new JProperty(library.Name + DependencyContextStrings.VersionSeperator + library.Version, WriteTargetLibrary(library))));
}
private JObject WritePortableTarget(IReadOnlyList<RuntimeLibrary> runtimeLibraries, IReadOnlyList<CompilationLibrary> compilationLibraries)
{
var runtimeLookup = runtimeLibraries.ToDictionary(l => l.Name);
var compileLookup = compilationLibraries.ToDictionary(l => l.Name);
var targetObject = new JObject();
foreach (var packageName in runtimeLookup.Keys.Concat(compileLookup.Keys).Distinct())
{
RuntimeLibrary runtimeLibrary;
runtimeLookup.TryGetValue(packageName, out runtimeLibrary);
CompilationLibrary compilationLibrary;
compileLookup.TryGetValue(packageName, out compilationLibrary);
if (compilationLibrary != null && runtimeLibrary != null)
{
Debug.Assert(compilationLibrary.Serviceable == runtimeLibrary.Serviceable);
Debug.Assert(compilationLibrary.Version == runtimeLibrary.Version);
Debug.Assert(compilationLibrary.Hash == runtimeLibrary.Hash);
Debug.Assert(compilationLibrary.Type == runtimeLibrary.Type);
}
var library = (Library)compilationLibrary ?? (Library)runtimeLibrary;
targetObject.Add(
new JProperty(library.Name + DependencyContextStrings.VersionSeperator + library.Version,
WritePortableTargetLibrary(runtimeLibrary, compilationLibrary)
)
);
}
return targetObject;
}
private void AddCompilationAssemblies(JObject libraryObject, IEnumerable<string> compilationAssemblies)
{
if (!compilationAssemblies.Any())
{
return;
}
libraryObject.Add(new JProperty(DependencyContextStrings.CompileTimeAssembliesKey,
WriteAssetList(compilationAssemblies))
);
}
private void AddRuntimeAssemblies(JObject libraryObject, IEnumerable<RuntimeAssembly> runtimeAssemblies)
{
if (!runtimeAssemblies.Any())
{
return;
}
libraryObject.Add(new JProperty(DependencyContextStrings.RuntimeAssembliesKey,
WriteAssetList(runtimeAssemblies.Select(a => a.Path)))
);
}
private void AddDependencies(JObject libraryObject, IEnumerable<Dependency> dependencies)
{
if (!dependencies.Any())
{
return;
}
libraryObject.AddFirst(
new JProperty(DependencyContextStrings.DependenciesPropertyName,
new JObject(
dependencies.Select(dependency => new JProperty(dependency.Name, dependency.Version))))
);
}
private void AddResourceAssemblies(JObject libraryObject, IEnumerable<ResourceAssembly> resourceAssemblies)
{
if (!resourceAssemblies.Any())
{
return;
}
libraryObject.Add(DependencyContextStrings.ResourceAssembliesPropertyName,
new JObject(resourceAssemblies.Select(a =>
new JProperty(NormalizePath(a.Path), new JObject(new JProperty(DependencyContextStrings.LocalePropertyName, a.Locale))))
)
);
}
private JObject WriteTargetLibrary(Library library)
{
var runtimeLibrary = library as RuntimeLibrary;
if (runtimeLibrary != null)
{
var libraryObject = new JObject();
AddDependencies(libraryObject, runtimeLibrary.Dependencies);
AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies);
AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies);
if (runtimeLibrary.NativeLibraries.Any())
{
libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries));
}
return libraryObject;
}
var compilationLibrary = library as CompilationLibrary;
if (compilationLibrary != null)
{
var libraryObject = new JObject();
AddDependencies(libraryObject, compilationLibrary.Dependencies);
AddCompilationAssemblies(libraryObject, compilationLibrary.Assemblies);
return libraryObject;
}
throw new NotSupportedException();
}
private JObject WritePortableTargetLibrary(RuntimeLibrary runtimeLibrary, CompilationLibrary compilationLibrary)
{
var libraryObject = new JObject();
var dependencies = new HashSet<Dependency>();
if (runtimeLibrary != null)
{
if (runtimeLibrary.RuntimeTargets.Any())
{
libraryObject.Add(new JProperty(
DependencyContextStrings.RuntimeTargetsPropertyName,
new JObject(runtimeLibrary.RuntimeTargets.SelectMany(WriteRuntimeTarget)))
);
}
AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies);
AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies);
libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries));
dependencies.UnionWith(runtimeLibrary.Dependencies);
}
if (compilationLibrary != null)
{
AddCompilationAssemblies(libraryObject, compilationLibrary.Assemblies);
dependencies.UnionWith(compilationLibrary.Dependencies);
}
AddDependencies(libraryObject, dependencies);
return libraryObject;
}
private IEnumerable<JProperty> WriteRuntimeTarget(RuntimeTarget target)
{
var runtime = WriteRuntimeTargetAssemblies(
target.Assemblies.Select(a => a.Path),
target.Runtime,
DependencyContextStrings.RuntimeAssetType);
var native = WriteRuntimeTargetAssemblies(
target.NativeLibraries,
target.Runtime,
DependencyContextStrings.NativeAssetType);
return runtime.Concat(native);
}
private IEnumerable<JProperty> WriteRuntimeTargetAssemblies(IEnumerable<string> assemblies, string runtime, string assetType)
{
foreach (var assembly in assemblies)
{
yield return new JProperty(NormalizePath(assembly),
new JObject(
new JProperty(DependencyContextStrings.RidPropertyName, runtime),
new JProperty(DependencyContextStrings.AssetTypePropertyName, assetType)
)
);
}
}
private JObject WriteAssetList(IEnumerable<string> assetPaths)
{
return new JObject(assetPaths.Select(assembly => new JProperty(NormalizePath(assembly), new JObject())));
}
private JObject WriteLibraries(DependencyContext context)
{
var allLibraries =
context.RuntimeLibraries.Cast<Library>().Concat(context.CompileLibraries)
.GroupBy(library => library.Name + DependencyContextStrings.VersionSeperator + library.Version);
return new JObject(allLibraries.Select(libraries=> new JProperty(libraries.Key, WriteLibrary(libraries.First()))));
}
private JObject WriteLibrary(Library library)
{
return new JObject(
new JProperty(DependencyContextStrings.TypePropertyName, library.Type),
new JProperty(DependencyContextStrings.ServiceablePropertyName, library.Serviceable),
new JProperty(DependencyContextStrings.Sha512PropertyName, library.Hash)
);
}
private string NormalizePath(string path)
{
return path.Replace('\\', '/');
}
}
}

View File

@ -0,0 +1,9 @@
using System.IO;
namespace Microsoft.Extensions.DependencyModel
{
internal interface IDependencyContextReader
{
DependencyContext Read(Stream stream);
}
}

View File

@ -0,0 +1,33 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Linq;
using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyModel
{
internal class Library
{
public Library(string type, string name, string version, string hash, IEnumerable<Dependency> dependencies, bool serviceable)
{
Type = type;
Name = name;
Version = version;
Hash = hash;
Dependencies = dependencies.ToArray();
Serviceable = serviceable;
}
public string Type { get; }
public string Name { get; }
public string Version { get; }
public string Hash { get; }
public IReadOnlyList<Dependency> Dependencies { get; }
public bool Serviceable { get; }
}
}

View File

@ -0,0 +1,75 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal class AppBaseCompilationAssemblyResolver : ICompilationAssemblyResolver
{
private readonly string _basePath;
public AppBaseCompilationAssemblyResolver()
{
_basePath = PlatformServices.Default.Application.ApplicationBasePath;
}
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
{
var isProject = string.Equals(library.Type, "project", StringComparison.OrdinalIgnoreCase);
if (!isProject &&
!string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(library.Type, "referenceassembly", StringComparison.OrdinalIgnoreCase))
{
return false;
}
var refsPath = Path.Combine(_basePath, "refs");
var hasRefs = Directory.Exists(refsPath);
// Resolving packages and reference assebmlies requires refs folder to exist
if (!isProject && !hasRefs)
{
return false;
}
var directories = new List<string>()
{
_basePath
};
if (hasRefs)
{
directories.Insert(0, refsPath);
}
foreach (var assembly in library.Assemblies)
{
bool resolved = false;
var assemblyFile = Path.GetFileName(assembly);
foreach (var directory in directories)
{
string fullName;
if (ResolverUtils.TryResolveAssemblyFile(directory, assemblyFile, out fullName))
{
assemblies.Add(fullName);
resolved = true;
break;
}
}
if (!resolved)
{
throw new InvalidOperationException(
$"Can not find assembly file {assemblyFile} at '{string.Join(",", directories)}'");
}
}
return true;
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal class CompositeCompilationAssemblyResolver: ICompilationAssemblyResolver
{
private readonly ICompilationAssemblyResolver[] _resolvers;
public CompositeCompilationAssemblyResolver(ICompilationAssemblyResolver[] resolvers)
{
_resolvers = resolvers;
}
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
{
foreach (var resolver in _resolvers)
{
if (resolver.TryResolveAssemblyPaths(library, assemblies))
{
return true;
}
}
return false;;
}
}
}

View File

@ -0,0 +1,58 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal class DotNetReferenceAssembliesPathResolver
{
public static readonly string DotNetReferenceAssembliesPathEnv = "DOTNET_REFERENCE_ASSEMBLIES_PATH";
internal static string Resolve(IRuntimeEnvironment runtimeEnvironment)
{
var path = Environment.GetEnvironmentVariable(DotNetReferenceAssembliesPathEnv);
if (!string.IsNullOrEmpty(path))
{
return path;
}
return GetDefaultDotNetReferenceAssembliesPath(runtimeEnvironment);
}
public static string Resolve()
{
return Resolve(PlatformServices.Default.Runtime);
}
private static string GetDefaultDotNetReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment)
{
var os = runtimeEnvironment.OperatingSystemPlatform;
if (os == Platform.Windows)
{
return null;
}
if (os == Platform.Darwin &&
Directory.Exists("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks"))
{
return "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks";
}
if (Directory.Exists("/usr/local/lib/mono/xbuild-frameworks"))
{
return "/usr/local/lib/mono/xbuild-frameworks";
}
if (Directory.Exists("/usr/lib/mono/xbuild-frameworks"))
{
return "/usr/lib/mono/xbuild-frameworks";
}
return null;
}
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal interface ICompilationAssemblyResolver
{
bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies);
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal class PackageCacheCompilationAssemblyResolver: ICompilationAssemblyResolver
{
private readonly string _packageCacheDirectory;
internal PackageCacheCompilationAssemblyResolver()
{
_packageCacheDirectory = Environment.GetEnvironmentVariable("DOTNET_PACKAGES_CACHE");
}
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
{
if (!string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (!string.IsNullOrEmpty(_packageCacheDirectory))
{
var hashSplitterPos = library.Hash.IndexOf('-');
if (hashSplitterPos <= 0 || hashSplitterPos == library.Hash.Length - 1)
{
throw new InvalidOperationException($"Invalid hash entry '{library.Hash}' for package '{library.Name}'");
}
string packagePath;
if (ResolverUtils.TryResolvePackagePath(library, _packageCacheDirectory, out packagePath))
{
var hashAlgorithm = library.Hash.Substring(0, hashSplitterPos);
var cacheHashPath = Path.Combine(packagePath, $"{library.Name}.{library.Version}.nupkg.{hashAlgorithm}");
if (File.Exists(cacheHashPath) &&
File.ReadAllText(cacheHashPath) == library.Hash.Substring(hashSplitterPos + 1))
{
assemblies.AddRange(ResolverUtils.ResolveFromPackagePath(library, packagePath));
return true;
}
}
}
return false;
}
}
}

View File

@ -0,0 +1,63 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal class PackageCompilationAssemblyResolver: ICompilationAssemblyResolver
{
private readonly string _nugetPackageDirectory;
internal PackageCompilationAssemblyResolver()
{
_nugetPackageDirectory = GetDefaultPackageDirectory(PlatformServices.Default.Runtime);
}
internal static string GetDefaultPackageDirectory(IRuntimeEnvironment runtimeEnvironment)
{
var packageDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
if (!string.IsNullOrEmpty(packageDirectory))
{
return packageDirectory;
}
string basePath;
if (runtimeEnvironment.OperatingSystemPlatform == Platform.Windows)
{
basePath = Environment.GetEnvironmentVariable("USERPROFILE");
}
else
{
basePath = Environment.GetEnvironmentVariable("HOME");
}
if (string.IsNullOrEmpty(basePath))
{
return null;
}
return Path.Combine(basePath, ".nuget", "packages");
}
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
{
if (string.IsNullOrEmpty(_nugetPackageDirectory) ||
!string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase))
{
return false;
}
string packagePath;
if (ResolverUtils.TryResolvePackagePath(library, _nugetPackageDirectory, out packagePath))
{
assemblies.AddRange(ResolverUtils.ResolveFromPackagePath(library, packagePath));
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,121 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal class ReferenceAssemblyPathResolver: ICompilationAssemblyResolver
{
private readonly string _defaultReferenceAssembliesPath;
private readonly string[] _fallbackSearchPaths;
internal ReferenceAssemblyPathResolver()
{
_defaultReferenceAssembliesPath = GetDefaultReferenceAssembliesPath(PlatformServices.Default.Runtime);
_fallbackSearchPaths = GetFallbackSearchPaths(PlatformServices.Default.Runtime);
}
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
{
if (!string.Equals(library.Type, "referenceassembly", StringComparison.OrdinalIgnoreCase))
{
return false;
}
foreach (var assembly in library.Assemblies)
{
string fullName;
if (!TryResolveReferenceAssembly(assembly, out fullName))
{
throw new InvalidOperationException($"Can not find reference assembly '{assembly}' file for package {library.Name}");
}
assemblies.Add(fullName);
}
return true;
}
private bool TryResolveReferenceAssembly(string path, out string fullPath)
{
fullPath = null;
if (_defaultReferenceAssembliesPath != null)
{
var relativeToReferenceAssemblies = Path.Combine(_defaultReferenceAssembliesPath, path);
if (File.Exists(relativeToReferenceAssemblies))
{
fullPath = relativeToReferenceAssemblies;
return true;
}
}
var name = Path.GetFileName(path);
foreach (var fallbackPath in _fallbackSearchPaths)
{
var fallbackFile = Path.Combine(fallbackPath, name);
if (File.Exists(fallbackFile))
{
fullPath = fallbackFile;
return true;
}
}
return false;
}
internal static string[] GetFallbackSearchPaths(IRuntimeEnvironment runtimeEnvironment)
{
if (runtimeEnvironment.OperatingSystemPlatform != Platform.Windows)
{
return new string[0];
}
var net20Dir = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v2.0.50727");
if (!Directory.Exists(net20Dir))
{
return new string[0];
}
return new[] { net20Dir };
}
internal static string GetDefaultReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment)
{
// Allow setting the reference assemblies path via an environment variable
var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(runtimeEnvironment);
if (!string.IsNullOrEmpty(referenceAssembliesPath))
{
return referenceAssembliesPath;
}
if (runtimeEnvironment.OperatingSystemPlatform != Platform.Windows)
{
// There is no reference assemblies path outside of windows
// The environment variable can be used to specify one
return null;
}
// References assemblies are in %ProgramFiles(x86)% on
// 64 bit machines
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
if (string.IsNullOrEmpty(programFiles))
{
// On 32 bit machines they are in %ProgramFiles%
programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
}
if (string.IsNullOrEmpty(programFiles))
{
// Reference assemblies aren't installed
return null;
}
return Path.Combine(
programFiles,
"Reference Assemblies", "Microsoft", "Framework");
}
}
}

View File

@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
namespace Microsoft.Extensions.DependencyModel.Resolution
{
internal static class ResolverUtils
{
internal static bool TryResolvePackagePath(CompilationLibrary library, string basePath, out string packagePath)
{
packagePath = Path.Combine(basePath, library.Name, library.Version);
if (Directory.Exists(packagePath))
{
return true;
}
return false;
}
internal static IEnumerable<string> ResolveFromPackagePath(CompilationLibrary library, string basePath)
{
foreach (var assembly in library.Assemblies)
{
string fullName;
if (!TryResolveAssemblyFile(basePath, assembly, out fullName))
{
throw new InvalidOperationException($"Can not find assembly file for package {library.Name} at '{fullName}'");
}
yield return fullName;
}
}
internal static bool TryResolveAssemblyFile(string basePath, string assemblyPath, out string fullName)
{
fullName = Path.Combine(basePath, assemblyPath);
if (File.Exists(fullName))
{
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.Extensions.DependencyModel
{
internal class ResourceAssembly
{
public ResourceAssembly(string path, string locale)
{
Locale = locale;
Path = path;
}
public string Locale { get; set; }
public string Path { get; set; }
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
namespace Microsoft.Extensions.DependencyModel
{
internal class RuntimeAssembly
{
private const string NativeImageSufix = ".ni";
private readonly string _assemblyName;
public RuntimeAssembly(string assemblyName, string path)
{
_assemblyName = assemblyName;
Path = path;
}
public AssemblyName Name => new AssemblyName(_assemblyName);
public string Path { get; }
public static RuntimeAssembly Create(string path)
{
var assemblyName = System.IO.Path.GetFileNameWithoutExtension(path);
if (assemblyName == null)
{
throw new ArgumentException($"Provided path has empty file name '{path}'", nameof(path));
}
if (assemblyName.EndsWith(NativeImageSufix))
{
assemblyName = assemblyName.Substring(0, assemblyName.Length - NativeImageSufix.Length);
}
return new RuntimeAssembly(assemblyName, path);
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class RuntimeFallbacks
{
public string Runtime { get; set; }
public IReadOnlyList<string> Fallbacks { get; set; }
public RuntimeFallbacks(string runtime, IEnumerable<string> fallbacks)
{
if (runtime == null)
{
throw new ArgumentNullException(nameof(runtime));
}
if (fallbacks == null)
{
throw new ArgumentNullException(nameof(fallbacks));
}
Runtime = runtime;
Fallbacks = fallbacks.ToArray();
}
}
}

View File

@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class RuntimeLibrary : Library
{
public RuntimeLibrary(
string type,
string name,
string version,
string hash,
IEnumerable<RuntimeAssembly> assemblies,
IEnumerable<string> nativeLibraries,
IEnumerable<ResourceAssembly> resourceAssemblies,
IEnumerable<RuntimeTarget> subTargets,
IEnumerable<Dependency> dependencies,
bool serviceable)
: base(type, name, version, hash, dependencies, serviceable)
{
Assemblies = assemblies.ToArray();
ResourceAssemblies = resourceAssemblies.ToArray();
RuntimeTargets = subTargets.ToArray();
NativeLibraries = nativeLibraries.ToArray();
}
public IReadOnlyList<RuntimeAssembly> Assemblies { get; }
public IReadOnlyList<string> NativeLibraries { get; }
public IReadOnlyList<ResourceAssembly> ResourceAssemblies { get; }
public IReadOnlyList<RuntimeTarget> RuntimeTargets { get; }
}
}

View File

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Extensions.DependencyModel
{
internal class RuntimeTarget
{
public RuntimeTarget(string runtime, IEnumerable<RuntimeAssembly> assemblies, IEnumerable<string> nativeLibraries)
{
Runtime = runtime;
Assemblies = assemblies.ToArray();
NativeLibraries = nativeLibraries.ToArray();
}
public string Runtime { get; }
public IReadOnlyList<RuntimeAssembly> Assemblies { get; }
public IReadOnlyList<string> NativeLibraries { get; }
}
}

View File

@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
/// </summary>
/// <returns>A set of <see cref="Library"/>.</returns>
// Internal for unit testing
protected internal virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
internal virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
{
if (ReferenceAssemblies == null)
{

View File

@ -24,7 +24,6 @@
"version": "1.0.0-*"
},
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
"Microsoft.Extensions.DependencyModel": "1.0.0-*",
"Microsoft.Extensions.ClosedGenericMatcher.Sources": {
"version": "1.0.0-*",
"type": "build"
@ -34,6 +33,7 @@
"type": "build",
"version": "1.0.0-*"
},
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-*",
"Microsoft.Extensions.PropertyActivator.Sources": {
"version": "1.0.0-*",
"type": "build"
@ -46,6 +46,7 @@
"version": "1.0.0-*",
"type": "build"
},
"Newtonsoft.Json": "8.0.3",
"System.Buffers": "4.0.0-*",
"System.Diagnostics.DiagnosticSource": "4.0.0-*"
},

View File

@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
var parseOptions = options.ParseOptions;
parseOptions = parseOptions.WithPreprocessorSymbols(
parseOptions.PreprocessorSymbolNames.Concat(compilationOptions.Defines));
parseOptions.PreprocessorSymbolNames.Concat(compilationOptions.Defines ?? Enumerable.Empty<string>()));
LanguageVersion languageVersion;
if (!string.IsNullOrEmpty(compilationOptions.LanguageVersion) &&

View File

@ -13,6 +13,7 @@
],
"xmlDoc": true
},
"compile": "../Microsoft.AspNetCore.Mvc.Core/DependencyContext/**/*.cs",
"dependencies": {
"Microsoft.AspNetCore.Mvc.Razor.Host": "1.0.0-*",
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0-*",
@ -44,7 +45,7 @@
"netstandard1.5": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
"portable-net451+win8"
],
"dependencies": {
"System.Text.Encoding": "4.0.11-*",

View File

@ -1,220 +0,0 @@
// 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<string>
{
"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<string> referenceAssemblies)
: base(entryAssembly, dependencyContext)
{
ReferenceAssemblies = referenceAssemblies;
}
protected override HashSet<string> ReferenceAssemblies { get; }
}
private class TestableAssemblyProvider : DefaultAssemblyProvider
{
public TestableAssemblyProvider(
Assembly entryAssembly,
DependencyContext dependencyContext)
: base(entryAssembly, dependencyContext)
{
}
public new HashSet<string> ReferenceAssemblies => base.ReferenceAssemblies;
}
}
}

View File

@ -1,425 +0,0 @@
// 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.Reflection;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class DefaultRoslynCompilationServiceTest
{
[Fact]
public void Compile_ReturnsCompilationResult()
{
// Arrange
var content = @"
public class MyTestType {}";
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
GetOptions(),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.Equal("MyTestType", result.CompiledType.Name);
}
[Fact]
public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
{
// Arrange
var viewPath = "some-relative-path";
var fileContent = "test file content";
var content = $@"
#line 1 ""{viewPath}""
this should fail";
var fileProvider = new TestFileProvider();
var fileInfo = fileProvider.AddFile(viewPath, fileContent);
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
GetOptions(),
GetFileProviderAccessor(fileProvider),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.IsType<CompilationResult>(result);
Assert.Null(result.CompiledType);
var compilationFailure = Assert.Single(result.CompilationFailures);
Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
Assert.Equal(fileContent, compilationFailure.SourceFileContent);
}
[Fact]
public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
{
// Arrange
var fileContent = "file content";
var content = @"this should fail";
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
GetOptions(),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { Content = fileContent },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.IsType<CompilationResult>(result);
Assert.Null(result.CompiledType);
var compilationFailure = Assert.Single(result.CompilationFailures);
Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
Assert.Equal(content, compilationFailure.SourceFileContent);
}
[Fact]
public void Compile_DoesNotThrow_IfFileCannotBeRead()
{
// Arrange
var path = "some-relative-path";
var content = $@"
#line 1 ""{path}""
this should fail";
var mockFileInfo = new Mock<IFileInfo>();
mockFileInfo.Setup(f => f.CreateReadStream())
.Throws(new Exception());
var fileProvider = new TestFileProvider();
fileProvider.AddFile(path, mockFileInfo.Object);
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
GetOptions(),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.IsType<CompilationResult>(result);
Assert.Null(result.CompiledType);
var compilationFailure = Assert.Single(result.CompilationFailures);
Assert.Equal(path, compilationFailure.SourceFilePath);
Assert.Null(compilationFailure.SourceFileContent);
}
[Fact]
public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
{
// Arrange
var content = @"
#if MY_CUSTOM_DEFINE
public class MyCustomDefinedClass {}
#else
public class MyNonCustomDefinedClass {}
#endif
";
var options = GetOptions();
options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE");
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
options,
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.NotNull(result.CompiledType);
Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
}
[Fact]
public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
{
// Arrange
var viewPath = "Views/Home/Index";
var generatedCodeFileName = "Generated Code";
var fileProvider = new TestFileProvider();
fileProvider.AddFile(viewPath, "view-content");
var options = new RazorViewEngineOptions();
options.FileProviders.Add(fileProvider);
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
options,
GetFileProviderAccessor(fileProvider),
NullLoggerFactory.Instance);
var assemblyName = "random-assembly-name";
var diagnostics = new[]
{
Diagnostic.Create(
GetDiagnosticDescriptor("message-1"),
Location.Create(
viewPath,
new TextSpan(10, 5),
new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))),
Diagnostic.Create(
GetDiagnosticDescriptor("message-2"),
Location.Create(
assemblyName,
new TextSpan(1, 6),
new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))),
Diagnostic.Create(
GetDiagnosticDescriptor("message-3"),
Location.Create(
viewPath,
new TextSpan(40, 50),
new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))),
};
// Act
var compilationResult = compilationService.GetCompilationFailedResult(
viewPath,
"compilation-content",
assemblyName,
diagnostics);
// Assert
Assert.Collection(compilationResult.CompilationFailures,
failure =>
{
Assert.Equal(viewPath, failure.SourceFilePath);
Assert.Equal("view-content", failure.SourceFileContent);
Assert.Collection(failure.Messages,
message =>
{
Assert.Equal("message-1", message.Message);
Assert.Equal(viewPath, message.SourceFilePath);
Assert.Equal(11, message.StartLine);
Assert.Equal(2, message.StartColumn);
Assert.Equal(11, message.EndLine);
Assert.Equal(3, message.EndColumn);
},
message =>
{
Assert.Equal("message-3", message.Message);
Assert.Equal(viewPath, message.SourceFilePath);
Assert.Equal(31, message.StartLine);
Assert.Equal(6, message.StartColumn);
Assert.Equal(41, message.EndLine);
Assert.Equal(13, message.EndColumn);
});
},
failure =>
{
Assert.Equal(generatedCodeFileName, failure.SourceFilePath);
Assert.Equal("compilation-content", failure.SourceFileContent);
Assert.Collection(failure.Messages,
message =>
{
Assert.Equal("message-2", message.Message);
Assert.Equal(assemblyName, message.SourceFilePath);
Assert.Equal(2, message.StartLine);
Assert.Equal(3, message.StartColumn);
Assert.Equal(4, message.EndLine);
Assert.Equal(5, message.EndColumn);
});
});
}
[Fact]
public void Compile_RunsCallback()
{
// Arrange
var content = "public class MyTestType {}";
RoslynCompilationContext usedCompilation = null;
var compilationService = new DefaultRoslynCompilationService(
GetDependencyContext(),
GetOptions(callback: c => usedCompilation = c),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
Assert.NotNull(usedCompilation);
Assert.Single(usedCompilation.Compilation.SyntaxTrees);
}
[Fact]
public void Compile_ThrowsIfDependencyContextIsNullAndTheApplicationFailsToCompileWithNoReferences()
{
// Arrange
var content = "public class MyTestType {}";
var compilationService = new DefaultRoslynCompilationService(
dependencyContext: null,
viewEngineOptions: GetOptions(),
fileProviderAccessor: GetFileProviderAccessor(),
loggerFactory: NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path.cshtml");
var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your "
+ "application's project.json sets the 'preserveCompilationContext' compilation property.";
// Act and Assert
var ex = Assert.Throws<InvalidOperationException>(() =>
compilationService.Compile(relativeFileInfo, content));
Assert.Equal(expected, ex.Message);
}
[Fact]
public void Compile_ThrowsIfDependencyContextReturnsNoReferencesAndTheApplicationFailsToCompile()
{
// Arrange
var content = "public class MyTestType {}";
var dependencyContext = new DependencyContext(
target: null,
runtime: null,
compilationOptions: Extensions.DependencyModel.CompilationOptions.Default,
compileLibraries: new CompilationLibrary[0],
runtimeLibraries: new RuntimeLibrary[0]);
var compilationService = new DefaultRoslynCompilationService(
dependencyContext: dependencyContext,
viewEngineOptions: GetOptions(),
fileProviderAccessor: GetFileProviderAccessor(),
loggerFactory: NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path.cshtml");
var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your "
+ "application's project.json sets the 'preserveCompilationContext' compilation property.";
// Act and Assert
var ex = Assert.Throws<InvalidOperationException>(() =>
compilationService.Compile(relativeFileInfo, content));
Assert.Equal(expected, ex.Message);
}
[Fact]
public void Compile_DoesNotThrowIfReferencesWereClearedInCallback()
{
// Arrange
var options = GetOptions(context =>
{
context.Compilation = context.Compilation.RemoveAllReferences();
});
var content = "public class MyTestType {}";
var compilationService = new DefaultRoslynCompilationService(
dependencyContext: GetDependencyContext(),
viewEngineOptions: options,
fileProviderAccessor: GetFileProviderAccessor(),
loggerFactory: NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path.cshtml");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.Single(result.CompilationFailures);
}
[Fact]
public void Compile_SucceedsIfReferencesAreAddedInCallback()
{
// Arrange
var options = GetOptions(context =>
{
var assemblyLocation = typeof(object).GetTypeInfo().Assembly.Location;
context.Compilation = context
.Compilation
.AddReferences(MetadataReference.CreateFromFile(assemblyLocation));
});
var content = "public class MyTestType {}";
var compilationService = new DefaultRoslynCompilationService(
dependencyContext: null,
viewEngineOptions: options,
fileProviderAccessor: GetFileProviderAccessor(),
loggerFactory: NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path.cshtml");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.Null(result.CompilationFailures);
Assert.NotNull(result.CompiledType);
}
private static DiagnosticDescriptor GetDiagnosticDescriptor(string messageFormat)
{
return new DiagnosticDescriptor(
id: "someid",
title: "sometitle",
messageFormat: messageFormat,
category: "some-category",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
private static RazorViewEngineOptions GetOptions(Action<RoslynCompilationContext> callback = null)
{
return new RazorViewEngineOptions
{
CompilationCallback = callback ?? (c => { }),
};
}
private IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null)
{
var options = new Mock<IRazorViewEngineFileProviderAccessor>();
options.SetupGet(o => o.FileProvider)
.Returns(fileProvider ?? new TestFileProvider());
return options.Object;
}
private DependencyContext GetDependencyContext()
{
var assembly = typeof(DefaultRoslynCompilationServiceTest).GetTypeInfo().Assembly;
return DependencyContext.Load(assembly);
}
}
}