1212
1313 public abstract class ContextAwareTask : Task
1414 {
15+ #if NETCOREAPP2_0
16+ /// <summary>
17+ /// Our custom <see cref="AssemblyLoadContext"/> that we create to host our Task.
18+ /// </summary>
19+ /// <remarks>
20+ /// We only create *one* of these, and reuse it for subsequent task invocations,
21+ /// because creating multiple of them hit https://github.com/dotnet/coreclr/issues/19654
22+ /// </remarks>
23+ private static CustomAssemblyLoader Loader ;
24+ #endif
25+
1526 protected virtual string ManagedDllDirectory => Path . GetDirectoryName ( new Uri ( this . GetType ( ) . GetTypeInfo ( ) . Assembly . CodeBase ) . LocalPath ) ;
1627
1728 protected virtual string UnmanagedDllDirectory => null ;
@@ -20,8 +31,13 @@ public override bool Execute()
2031 {
2132#if NETCOREAPP2_0
2233 string taskAssemblyPath = new Uri ( this . GetType ( ) . GetTypeInfo ( ) . Assembly . CodeBase ) . LocalPath ;
23- var ctxt = new CustomAssemblyLoader ( this ) ;
24- Assembly inContextAssembly = ctxt . LoadFromAssemblyPath ( taskAssemblyPath ) ;
34+ if ( Loader == null )
35+ {
36+ Loader = new CustomAssemblyLoader ( ) ;
37+ }
38+
39+ Loader . LoaderTask = this ;
40+ Assembly inContextAssembly = Loader . LoadFromAssemblyPath ( taskAssemblyPath ) ;
2541 Type innerTaskType = inContextAssembly . GetType ( this . GetType ( ) . FullName ) ;
2642 object innerTask = Activator . CreateInstance ( innerTaskType ) ;
2743
@@ -71,31 +87,41 @@ public override bool Execute()
7187#if NETCOREAPP2_0
7288 private class CustomAssemblyLoader : AssemblyLoadContext
7389 {
74- private readonly ContextAwareTask loaderTask ;
90+ private ContextAwareTask loaderTask ;
7591
76- internal CustomAssemblyLoader ( ContextAwareTask loaderTask )
92+ internal CustomAssemblyLoader ( )
7793 {
78- this . loaderTask = loaderTask ;
94+ }
95+
96+ internal ContextAwareTask LoaderTask
97+ {
98+ get => this . loaderTask ;
99+ set => this . loaderTask = value ;
79100 }
80101
81102 protected override Assembly Load ( AssemblyName assemblyName )
82103 {
83- // Always load libgit2sharp in the default context.
84- // Something about the p/invoke done in that library with its custom marshaler
85- // doesn't sit well with Core CLR 2.x.
86- // See https://github.com/AArnott/Nerdbank.GitVersioning/issues/215 and https://github.com/dotnet/coreclr/issues/19654
87- AssemblyLoadContext preferredContext = assemblyName . Name . Equals ( "libgit2sharp" , StringComparison . OrdinalIgnoreCase ) ? Default : this ;
104+ if ( this . loaderTask == null )
105+ {
106+ throw new InvalidOperationException ( nameof ( this . loaderTask ) + " must be set first." ) ;
107+ }
108+
88109 string assemblyPath = Path . Combine ( this . loaderTask . ManagedDllDirectory , assemblyName . Name ) + ".dll" ;
89110 if ( File . Exists ( assemblyPath ) )
90111 {
91- return preferredContext . LoadFromAssemblyPath ( assemblyPath ) ;
112+ return this . LoadFromAssemblyPath ( assemblyPath ) ;
92113 }
93114
94115 return Default . LoadFromAssemblyName ( assemblyName ) ;
95116 }
96117
97118 protected override IntPtr LoadUnmanagedDll ( string unmanagedDllName )
98119 {
120+ if ( this . loaderTask == null )
121+ {
122+ throw new InvalidOperationException ( nameof ( this . loaderTask ) + " must be set first." ) ;
123+ }
124+
99125 string unmanagedDllPath = Directory . EnumerateFiles (
100126 this . loaderTask . UnmanagedDllDirectory ,
101127 $ "{ unmanagedDllName } .*") . Concat (
0 commit comments