November Happy Hour will be moved to Thursday December 5th.

EPiServer.Find.UnifiedSearch.ForInstanceOf throws exception under certain conditions

Found in

EPiServer.Find 13.2.2

Fixed in

EPiServer.Find 13.3.0

(Or a related package)

Created

Sep 11, 2019

Updated

Dec 07, 2022

State

Closed, Fixed and tested


Description

Fixed issue where EPiServer.Find.UnifiedSearch.ForInstanceOf throws exceptions under certain conditions.

Issue Description

Extension method:
public static UnifiedSearchTypeRulesBuilder<T> ForInstanceOf<T>(this IUnifiedSearchRegistry registry)

in EPiServer.Find, Version=13.2.2.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7 will throw ReflectionTypeLoadException if an assembly that is loaded into the excecution context cannot in turn load all of its direct and indirect dependencies (recursively).

There are many real-world situations where this can happen. Here it is a case of using the NuGet package "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", which allows the use of Roslyn compilers when compiling ASP.NET pages in runtime for example).

Steps to Reproduce

1. Do something causing an assembly to be present in the bin folder hierarchy that does not have access to all it's (recursive) dependencies.
2. Load all assemblies into execution context, perhaps during a scan of the bin folder for something via reflection.
3. Call UnifiedSearchTypeRulesBuilder<T> ForInstanceOf<T>(this IUnifiedSearchRegistry registry)
the method will now throw a ReflectionTypeLoadException when it calls Assembly.GetTypes().
_______________________________________________________________________________________________________

Steps to reproduce in Alloy Demo:
1. Add nuget package "Microsoft.CodeDom.Providers.DotNetCompilerPlatform".
2. Edit the BuildQuery() method in FindSearchPageController.cs like this:
...
private static void FakePreLoadAssemblies()

Unknown macro: { string binDirectory = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath); DirectoryInfo di = new DirectoryInfo(binDirectory); Assembly[] assemblies = di.GetFiles("*.dll", SearchOption.AllDirectories).Select(fi => fi.FullName).Where(fn => fn.IndexOf("native", StringComparison.OrdinalIgnoreCase) < 0).Select(fn => Assembly.LoadFrom(fn)).ToArray(); }

private ITypeSearch<ISearchContent> BuildQuery(FindSearchContentModel model, string selectedAnalyzer)
{
var language = searchClient.Settings.Languages.GetSupportedLanguage(selectedAnalyzer);

FakePreLoadAssemblies();
searchClient.Conventions.UnifiedSearchRegistry.ForInstanceOf<ArticlePage>();
...

Compile, run and search. It will now fail with a ReflectionTypeLoadException.