Skip to content
This repository was archived by the owner on Sep 17, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 68 additions & 5 deletions src/RoslynCodeTaskFactory/CodeTaskFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ public sealed partial class CodeTaskFactory : ITaskFactory
/// </summary>
private static readonly ConcurrentDictionary<TaskInfo, Assembly> CompiledAssemblyCache = new ConcurrentDictionary<TaskInfo, Assembly>();

/// <summary>
/// Stores a cache of loaded assemblies by the <see cref="AppDomain.AssemblyResolve"/> handler.
/// </summary>
private static readonly ConcurrentDictionary<string, Assembly> LoadedAssemblyCache = new ConcurrentDictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);

/// <summary>
/// Stores the path to the directory that this assembly is located in.
/// </summary>
private static readonly Lazy<string> ThisAssemblyDirectoryLazy = new Lazy<string>(() => Path.GetDirectoryName(typeof(CodeTaskFactory).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName));

/// <summary>
/// Stores the parent directory of this assembly's directory.
/// </summary>
private static readonly Lazy<string> ThisAssemblyParentDirectoryLazy = new Lazy<string>(() => Path.GetDirectoryName(ThisAssemblyDirectoryLazy.Value));

/// <summary>
/// Stores an instance of a <see cref="TaskLoggingHelper"/> for logging messages.
/// </summary>
Expand Down Expand Up @@ -121,6 +136,10 @@ public sealed partial class CodeTaskFactory : ITaskFactory
/// <inheritdoc cref="ITaskFactory.CleanupTask(ITask)"/>
public void CleanupTask(ITask task)
{
#if NET46

AppDomain.CurrentDomain.AssemblyResolve -= AppDomain_AssemblyResolve;
#endif
}

/// <inheritdoc cref="ITaskFactory.CreateTask(IBuildEngine)"/>
Expand Down Expand Up @@ -169,6 +188,11 @@ public bool Initialize(string taskName, IDictionary<string, TaskPropertyInfo> pa
TaskType = assembly.GetExportedTypes().FirstOrDefault(type => type.Name.Equals(taskName));
}

#if NET46

AppDomain.CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve;
#endif

// Initialization succeeded if we found a type matching the task name from the compiled assembly
//
return TaskType != null;
Expand Down Expand Up @@ -443,10 +467,6 @@ internal static bool TryLoadTaskBody(TaskLoggingHelper log, string taskName, str
/// can compile their own task library.</remarks>
internal static bool TryResolveAssemblyReferences(TaskLoggingHelper log, TaskInfo taskInfo, out ITaskItem[] items)
{
// Use the parent directory of this assembly as a starting point for resolving assemblies
//
string thisAssemblyParentDirectory = Path.GetDirectoryName(Path.GetDirectoryName(typeof(CodeTaskFactory).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName));

// Store the list of resolved assemblies because a user can specify a short name or a full path
//
ISet<string> resolvedAssemblyReferences = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
Expand Down Expand Up @@ -486,7 +506,7 @@ internal static bool TryResolveAssemblyReferences(TaskLoggingHelper log, TaskInf
? reference
: $"{reference}.dll";

string possiblePath = Path.Combine(thisAssemblyParentDirectory, ReferenceAssemblyDirectoryName, assemblyFileName);
string possiblePath = Path.Combine(ThisAssemblyParentDirectoryLazy.Value, ReferenceAssemblyDirectoryName, assemblyFileName);

if (File.Exists(possiblePath))
{
Expand Down Expand Up @@ -570,6 +590,49 @@ private static IEnumerable<string> GetPropertyStatements(string codeLanguage, IE
}
}

#if NET46

/// <summary>
/// A custom <see cref="AppDomain.AssemblyResolve"/> handler which loads assemblies needed for the CodeTaskFactory to work.
/// </summary>
/// <returns></returns>
private Assembly AppDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AssemblyName assemblyName = new AssemblyName(args.Name);

// Guess the path based on the name
//
string candidateAssemblyPath = Path.Combine(ThisAssemblyDirectoryLazy.Value, $"{assemblyName.Name}.dll");

// See if the assembly has already been loaded from this path
//
if (LoadedAssemblyCache.TryGetValue(candidateAssemblyPath, out Assembly loadedAssembly))
{
return loadedAssembly;
}

if (File.Exists(candidateAssemblyPath))
{
AssemblyName candidateAssemblyName = AssemblyName.GetAssemblyName(candidateAssemblyPath);

// Verify that the requested assembly is the same as this one
//
if (assemblyName.FullName.Equals(candidateAssemblyName.FullName, StringComparison.OrdinalIgnoreCase))
{
loadedAssembly = Assembly.LoadFrom(candidateAssemblyPath);

// Cache the loaded assembly for later if necessary
//
LoadedAssemblyCache.TryAdd(candidateAssemblyPath, loadedAssembly);

return loadedAssembly;
}
}
return null;
}

#endif

/// <summary>
/// Loads an assembly from the specified path.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/RoslynCodeTaskFactory/RoslynCodeTaskFactory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@
<BuildAction>Content</BuildAction>
<PackagePath>build\ref</PackagePath>
</_PackageFiles>

<_PackageFiles Include="lib\**">
<BuildAction>Content</BuildAction>
<PackagePath>build\</PackagePath>
</_PackageFiles>
</ItemGroup>

<ConvertToAbsolutePath Paths="$(OutputPath)">
Expand Down
Binary file not shown.