@@ -29,8 +29,9 @@ public partial class FunctionAssemblyLoadContext : AssemblyLoadContext
29
29
private static Lazy < FunctionAssemblyLoadContext > _defaultContext = new Lazy < FunctionAssemblyLoadContext > ( CreateSharedContext , true ) ;
30
30
31
31
private readonly List < string > _probingPaths = new List < string > ( ) ;
32
- private readonly IDictionary < string , string > _depsAssemblies ;
33
- private readonly IDictionary < string , string > _nativeLibraries ;
32
+ private readonly IDictionary < string , RuntimeAsset [ ] > _depsAssemblies ;
33
+ private readonly IDictionary < string , RuntimeAsset [ ] > _nativeLibraries ;
34
+ private readonly List < string > _currentRidFallback ;
34
35
35
36
public FunctionAssemblyLoadContext ( string basePath )
36
37
{
@@ -39,7 +40,9 @@ public FunctionAssemblyLoadContext(string basePath)
39
40
throw new ArgumentNullException ( nameof ( basePath ) ) ;
40
41
}
41
42
42
- ( _depsAssemblies , _nativeLibraries ) = InitializeDeps ( basePath ) ;
43
+ _currentRidFallback = DependencyHelper . GetRuntimeFallbacks ( ) ;
44
+
45
+ ( _depsAssemblies , _nativeLibraries ) = InitializeDeps ( basePath , _currentRidFallback ) ;
43
46
44
47
_probingPaths . Add ( basePath ) ;
45
48
}
@@ -51,26 +54,26 @@ internal static void ResetSharedContext()
51
54
_defaultContext = new Lazy < FunctionAssemblyLoadContext > ( CreateSharedContext , true ) ;
52
55
}
53
56
54
- internal static ( IDictionary < string , string > depsAssemblies , IDictionary < string , string > nativeLibraries ) InitializeDeps ( string basePath )
57
+ internal static ( IDictionary < string , RuntimeAsset [ ] > depsAssemblies , IDictionary < string , RuntimeAsset [ ] > nativeLibraries ) InitializeDeps ( string basePath , List < string > ridFallbacks )
55
58
{
56
59
string depsFilePath = Path . Combine ( basePath , DotNetConstants . FunctionsDepsFileName ) ;
57
60
58
61
if ( File . Exists ( depsFilePath ) )
59
62
{
60
63
try
61
64
{
62
- List < string > rids = DependencyHelper . GetRuntimeFallbacks ( ) ;
63
-
64
65
var reader = new DependencyContextJsonReader ( ) ;
65
66
using ( Stream file = File . OpenRead ( depsFilePath ) )
66
67
{
67
68
var depsContext = reader . Read ( file ) ;
68
- var depsAssemblies = depsContext . RuntimeLibraries . SelectMany ( l => SelectRuntimeAssemblyGroup ( rids , l . RuntimeAssemblyGroups ) )
69
- . ToDictionary ( path => Path . GetFileNameWithoutExtension ( path ) ) ;
69
+ var depsAssemblies = depsContext . RuntimeLibraries . SelectMany ( l => SelectRuntimeAssemblyGroup ( ridFallbacks , l . RuntimeAssemblyGroups ) )
70
+ . GroupBy ( a => Path . GetFileNameWithoutExtension ( a . Path ) )
71
+ . ToDictionary ( g => g . Key , g => g . ToArray ( ) , StringComparer . OrdinalIgnoreCase ) ;
70
72
71
73
// Note the difference here that nativeLibraries has the whole file name, including extension.
72
- var nativeLibraries = depsContext . RuntimeLibraries . SelectMany ( l => SelectRuntimeAssemblyGroup ( rids , l . NativeLibraryGroups ) )
73
- . ToDictionary ( path => Path . GetFileName ( path ) ) ;
74
+ var nativeLibraries = depsContext . RuntimeLibraries . SelectMany ( l => SelectRuntimeAssemblyGroup ( ridFallbacks , l . NativeLibraryGroups ) )
75
+ . GroupBy ( path => Path . GetFileName ( path . Path ) )
76
+ . ToDictionary ( g => g . Key , g => g . ToArray ( ) , StringComparer . OrdinalIgnoreCase ) ;
74
77
75
78
return ( depsAssemblies , nativeLibraries ) ;
76
79
}
@@ -83,20 +86,20 @@ internal static (IDictionary<string, string> depsAssemblies, IDictionary<string,
83
86
return ( null , null ) ;
84
87
}
85
88
86
- private static IEnumerable < string > SelectRuntimeAssemblyGroup ( List < string > rids , IReadOnlyList < RuntimeAssetGroup > runtimeAssemblyGroups )
89
+ private static IEnumerable < RuntimeAsset > SelectRuntimeAssemblyGroup ( List < string > rids , IReadOnlyList < RuntimeAssetGroup > runtimeAssemblyGroups )
87
90
{
88
91
// Attempt to load group for the current RID graph
89
92
foreach ( var rid in rids )
90
93
{
91
94
var assemblyGroup = runtimeAssemblyGroups . FirstOrDefault ( g => string . Equals ( g . Runtime , rid , StringComparison . OrdinalIgnoreCase ) ) ;
92
95
if ( assemblyGroup != null )
93
96
{
94
- return assemblyGroup . AssetPaths ;
97
+ return assemblyGroup . AssetPaths . Select ( path => new RuntimeAsset ( rid , path ) ) ;
95
98
}
96
99
}
97
100
98
101
// If unsuccessful, load default assets, making sure the path is flattened to reflect deployed files
99
- return runtimeAssemblyGroups . GetDefaultAssets ( ) . Select ( a => Path . GetFileName ( a ) ) ;
102
+ return runtimeAssemblyGroups . GetDefaultAssets ( ) . Select ( a => new RuntimeAsset ( null , Path . GetFileName ( a ) ) ) ;
100
103
}
101
104
102
105
private static FunctionAssemblyLoadContext CreateSharedContext ( )
@@ -224,7 +227,7 @@ private bool TryLoadDepsDependency(AssemblyName assemblyName, out Assembly assem
224
227
225
228
if ( _depsAssemblies != null &&
226
229
! IsRuntimeAssembly ( assemblyName ) &&
227
- _depsAssemblies . TryGetValue ( assemblyName . Name , out string assemblyPath ) )
230
+ TryGetDepsAsset ( _depsAssemblies , assemblyName . Name , _currentRidFallback , out string assemblyPath ) )
228
231
{
229
232
foreach ( var probingPath in _probingPaths )
230
233
{
@@ -240,6 +243,42 @@ private bool TryLoadDepsDependency(AssemblyName assemblyName, out Assembly assem
240
243
return assembly != null ;
241
244
}
242
245
246
+ internal static bool TryGetDepsAsset ( IDictionary < string , RuntimeAsset [ ] > depsAssets , string assetName , List < string > ridFallbacks , out string assemblyPath )
247
+ {
248
+ assemblyPath = null ;
249
+
250
+ if ( depsAssets . TryGetValue ( assetName , out RuntimeAsset [ ] assets ) )
251
+ {
252
+ // If we have a single asset match, return it:
253
+ if ( assets . Length == 1 )
254
+ {
255
+ assemblyPath = assets [ 0 ] . Path ;
256
+ }
257
+ else
258
+ {
259
+ foreach ( var rid in ridFallbacks )
260
+ {
261
+ RuntimeAsset match = assets . FirstOrDefault ( a => string . Equals ( rid , a . Rid , StringComparison . OrdinalIgnoreCase ) ) ;
262
+
263
+ if ( match != null )
264
+ {
265
+ assemblyPath = match . Path ;
266
+ break ;
267
+ }
268
+ }
269
+
270
+ // If we're unable to locate a matching asset based on the RID fallback probing,
271
+ // attempt to use a default/RID-agnostic asset instead
272
+ if ( assemblyPath == null )
273
+ {
274
+ assemblyPath = assets . FirstOrDefault ( a => a . Rid == null ) ? . Path ;
275
+ }
276
+ }
277
+ }
278
+
279
+ return assemblyPath != null ;
280
+ }
281
+
243
282
private bool TryLoadRuntimeAssembly ( AssemblyName assemblyName , out Assembly assembly )
244
283
{
245
284
assembly = null ;
@@ -320,7 +359,7 @@ private string GetRuntimeNativeAssetPath(string assetFileName)
320
359
321
360
if ( result == null && _nativeLibraries != null )
322
361
{
323
- if ( _nativeLibraries . TryGetValue ( assetFileName , out string relativePath ) )
362
+ if ( TryGetDepsAsset ( _nativeLibraries , assetFileName , _currentRidFallback , out string relativePath ) )
324
363
{
325
364
string nativeLibraryFullPath = Path . Combine ( basePath , relativePath ) ;
326
365
if ( File . Exists ( nativeLibraryFullPath ) )
0 commit comments