1
- // Copyright (c) .NET Foundation. All rights reserved.
1
+ // Copyright (c) .NET Foundation. All rights reserved.
2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . IO ;
7
7
using System . Linq ;
8
8
using System . Reflection ;
9
+ using System . Runtime . Loader ;
9
10
using Microsoft . AspNetCore . Mvc . Core ;
10
11
11
12
namespace Microsoft . AspNetCore . Mvc . ApplicationParts
@@ -16,7 +17,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
16
17
[ AttributeUsage ( AttributeTargets . Assembly , AllowMultiple = true ) ]
17
18
public sealed class RelatedAssemblyAttribute : Attribute
18
19
{
19
- private static readonly Func < string , Assembly > AssemblyLoadFileDelegate = Assembly . LoadFile ;
20
+ private static readonly Func < string , Assembly > LoadFromAssemblyPathDelegate =
21
+ AssemblyLoadContext . GetLoadContext ( typeof ( RelatedAssemblyAttribute ) . Assembly ) . LoadFromAssemblyPath ;
20
22
21
23
/// <summary>
22
24
/// Initializes a new instance of <see cref="RelatedAssemblyAttribute"/>.
@@ -50,7 +52,7 @@ public static IReadOnlyList<Assembly> GetRelatedAssemblies(Assembly assembly, bo
50
52
throw new ArgumentNullException ( nameof ( assembly ) ) ;
51
53
}
52
54
53
- return GetRelatedAssemblies ( assembly , throwOnError , File . Exists , AssemblyLoadFileDelegate ) ;
55
+ return GetRelatedAssemblies ( assembly , throwOnError , File . Exists , LoadFromAssemblyPathDelegate ) ;
54
56
}
55
57
56
58
internal static IReadOnlyList < Assembly > GetRelatedAssemblies (
@@ -66,7 +68,7 @@ internal static IReadOnlyList<Assembly> GetRelatedAssemblies(
66
68
67
69
// MVC will specifically look for related parts in the same physical directory as the assembly.
68
70
// No-op if the assembly does not have a location.
69
- if ( assembly . IsDynamic || string . IsNullOrEmpty ( assembly . Location ) )
71
+ if ( assembly . IsDynamic )
70
72
{
71
73
return Array . Empty < Assembly > ( ) ;
72
74
}
@@ -78,8 +80,10 @@ internal static IReadOnlyList<Assembly> GetRelatedAssemblies(
78
80
}
79
81
80
82
var assemblyName = assembly . GetName ( ) . Name ;
81
- var assemblyLocation = assembly . Location ;
82
- var assemblyDirectory = Path . GetDirectoryName ( assemblyLocation ) ;
83
+ // Assembly.Location may be null for a single-file exe. In this case, attempt to look for related parts in the app's base directory
84
+ var assemblyDirectory = string . IsNullOrEmpty ( assembly . Location ) ?
85
+ AppContext . BaseDirectory :
86
+ Path . GetDirectoryName ( assembly . Location ) ;
83
87
84
88
var relatedAssemblies = new List < Assembly > ( ) ;
85
89
for ( var i = 0 ; i < attributes . Length ; i ++ )
@@ -91,6 +95,22 @@ internal static IReadOnlyList<Assembly> GetRelatedAssemblies(
91
95
Resources . FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf ( nameof ( RelatedAssemblyAttribute ) , assemblyName ) ) ;
92
96
}
93
97
98
+ var relatedAssemblyName = new AssemblyName ( attribute . AssemblyFileName ) ;
99
+ Assembly relatedAssembly ;
100
+ try
101
+ {
102
+ // Perform a cursory check to determine if the Assembly has already been loaded
103
+ // before going to disk. In the ordinary case, related parts that are part of
104
+ // application's reference closure should already be loaded.
105
+ relatedAssembly = Assembly . Load ( relatedAssemblyName ) ;
106
+ relatedAssemblies . Add ( relatedAssembly ) ;
107
+ continue ;
108
+ }
109
+ catch ( IOException )
110
+ {
111
+ // The assembly isn't already loaded. Patience, we'll attempt to load it from disk next.
112
+ }
113
+
94
114
var relatedAssemblyLocation = Path . Combine ( assemblyDirectory , attribute . AssemblyFileName + ".dll" ) ;
95
115
if ( ! fileExists ( relatedAssemblyLocation ) )
96
116
{
@@ -106,7 +126,7 @@ internal static IReadOnlyList<Assembly> GetRelatedAssemblies(
106
126
}
107
127
}
108
128
109
- var relatedAssembly = loadFile ( relatedAssemblyLocation ) ;
129
+ relatedAssembly = loadFile ( relatedAssemblyLocation ) ;
110
130
relatedAssemblies . Add ( relatedAssembly ) ;
111
131
}
112
132
0 commit comments