Skip to content

Commit d1a7aca

Browse files
Binding Discovery: Wrap calls to .GetCustomAttributes in try/catch (#1006)
* Wrap calls to .GetCustomAttributes in try/catch in order to resiliently handle loading errors while reflecting during binding discovery. * Add comment about the error handling way Handle exceptions during type attribute loading and return false to prevent further error reporting. * Update CHANGELOG Added improvement to binding discovery and updated contributors. --------- Co-authored-by: Gáspár Nagy <gaspar.nagy@gmail.com>
1 parent b1da1fa commit d1a7aca

2 files changed

Lines changed: 28 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Improvements:
44

5+
* Improve binding discovery so that the discovery can continue even if the attributes of a type fail to load (#1006)
6+
57
## Bug fixes:
68
* Fix: xUnit VB.NET generates code with async warning (#1009)
79
* Fix: disableFriendlyTestNames doesn't work in Reqnroll 3.3.2 (#1013)

Reqnroll/Bindings/Discovery/RuntimeBindingRegistryBuilder.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,21 @@ public void BuildingCompleted()
7272
//internal - for testing
7373
internal bool BuildBindingsFromType(Type type)
7474
{
75-
// ReSharper disable PossibleMultipleEnumeration
76-
var filteredAttributes = type.GetCustomAttributes(typeof(Attribute), true).Cast<Attribute>().Where(attr => _bindingSourceProcessor.CanProcessTypeAttribute(attr.GetType().FullName));
75+
// ReSharper disable PossibleMultipleEnumeration
76+
// catch type attribute loading errors and continue;
77+
// if we cannot load an attribute, it must be because it comes from an assembly that is not relevant for Reqnroll bindings
78+
var reflectedAttributes = new List<Attribute>();
79+
try
80+
{
81+
reflectedAttributes.AddRange(type.GetCustomAttributes(true).Cast<Attribute>());
82+
}
83+
catch (Exception ex)
84+
{
85+
_bindingSourceProcessor.RegisterTypeLoadError($"Could not load attributes for type '{type.FullName}': {ex}");
86+
// When the type attributes cannot be loaded, the type cannot be processed anyway so we can return with false here to avoid reporting further errors.
87+
return false;
88+
}
89+
var filteredAttributes = reflectedAttributes.Where(attr => _bindingSourceProcessor.CanProcessTypeAttribute(attr.GetType().FullName));
7790
if (!_bindingSourceProcessor.PreFilterType(filteredAttributes.Select(attr => attr.GetType().FullName)))
7891
return false;
7992

@@ -94,12 +107,22 @@ internal bool BuildBindingsFromType(Type type)
94107

95108
private BindingSourceMethod CreateBindingSourceMethod(MethodInfo methodDefinition)
96109
{
110+
// catch method attribute loading errors and continue;
111+
var reflectedAttributes = new List<Attribute>();
112+
try
113+
{
114+
reflectedAttributes.AddRange(methodDefinition.GetCustomAttributes(true).Cast<Attribute>());
115+
}
116+
catch (Exception ex)
117+
{
118+
_bindingSourceProcessor.RegisterTypeLoadError($"Could not load attributes for method '{methodDefinition.DeclaringType?.FullName}.{methodDefinition.Name}': {ex}");
119+
}
97120
return new BindingSourceMethod
98121
{
99122
BindingMethod = new RuntimeBindingMethod(methodDefinition),
100123
IsPublic = methodDefinition.IsPublic,
101124
IsStatic = methodDefinition.IsStatic,
102-
Attributes = GetAttributes(methodDefinition.GetCustomAttributes(true).Cast<Attribute>().Where(attr => _bindingSourceProcessor.CanProcessTypeAttribute(attr.GetType().FullName)))
125+
Attributes = GetAttributes(reflectedAttributes.Where(attr => _bindingSourceProcessor.CanProcessTypeAttribute(attr.GetType().FullName)))
103126
};
104127
}
105128

0 commit comments

Comments
 (0)