forked from JamesRandall/FunctionMonkey
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConfigurationLocator.cs
125 lines (112 loc) · 5.07 KB
/
ConfigurationLocator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
using System;
using System.Linq;
using System.Reflection;
using System.Text;
using FunctionMonkey.Abstractions;
namespace FunctionMonkey
{
/// <summary>
/// Class that finds the configuration class
/// </summary>
public static class ConfigurationLocator
{
public static IFunctionAppConfiguration FindConfiguration()
{
// We scan the assemblies looking for:
//
// 1. An implementation of IFunctionAppConfiguration
//
// however the assembly containing it may not have been loaded (it its empty other than the builder) so next
// we look for:
//
// 2. A class called ReferenceLinkBack that has the ReferenceLinkBackAttribute on it and a single static
// method called ForceLinkBack
if (Scan(out var linkBackInfo, out var findConfiguration)) return findConfiguration;
// If we ge there then we found (2) but not an implementation of IFunctionAppConfiguration. That being the case
// we call that method. This will force the assembly to load, we rescane, and we should now find our implementation.
//
// This is a bit long-winded but I'm trying to avoid loading referenced assemblies myself in an already pretty
// complex runtime environment that is likely to already to have various resolution hooks.
if (linkBackInfo != null)
{
linkBackInfo.Invoke(null, null);
if (Scan(out var dummyLinkBackInfo, out var secondAttemptFindConfiguration)) return secondAttemptFindConfiguration;
}
throw new ConfigurationException("Unable to find implementation of IFunctionAppConfiguration");
}
private static bool Scan(out MethodInfo linkBackInfo, out IFunctionAppConfiguration findConfiguration)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.GetName().Name.StartsWith("Microsoft.")).ToArray();
linkBackInfo = null;
findConfiguration = null;
foreach (Assembly assembly in assemblies)
{
IFunctionAppConfiguration configuration = FindConfiguration(assembly);
if (configuration != null)
{
{
findConfiguration = configuration;
return true;
}
}
string assemblyName = assembly.GetName().Name;
if (assemblyName.EndsWith(".Functions.dll"))
{
Type[] candidateReferenceLinkBackTypes = assembly.GetTypes()
.Where(x => x.Name == "ReferenceLinkBack" && x.IsAbstract && x.IsSealed).ToArray();
if (candidateReferenceLinkBackTypes.Length == 1)
{
if (candidateReferenceLinkBackTypes[0].GetCustomAttributes<ReferenceLinkBackAttribute>().Any())
{
linkBackInfo = candidateReferenceLinkBackTypes[0].GetMethod("ForceLinkBack");
}
}
}
}
return false;
}
public static IFunctionAppConfiguration FindConfiguration(Assembly assembly)
{
if (assembly == null)
{
return FindConfiguration();
}
try
{
Type interfaceType = typeof(IFunctionAppConfiguration);
Type foundType = assembly.GetTypes().FirstOrDefault(x => interfaceType.IsAssignableFrom(x) && x.IsClass);
if (foundType != null)
{
return (IFunctionAppConfiguration)Activator.CreateInstance(foundType);
}
return null;
}
catch (ReflectionTypeLoadException rex)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"ReflectionTypeLoadException: {rex.Message}");
if (rex.Types != null)
{
sb.AppendLine("Unable to load types:");
foreach (Type loaderType in rex.Types)
{
sb.AppendLine(loaderType != null
? $" {loaderType.FullName}"
: " null type in ReflectionTypeLoadException");
}
}
if (rex.LoaderExceptions != null)
{
sb.AppendLine("With errors:");
foreach (var loaderException in rex.LoaderExceptions)
{
sb.AppendLine(loaderException != null
? $" {loaderException.GetType().Name}: {loaderException.Message}"
: " null LoadedException in ReflectionTypeLoadException");
}
}
throw new TypeLoadingException(sb.ToString());
}
}
}
}