WebApiAssembliesResolver class missing causing slow model build
Assemblies affected ASP.NET Core OData 8.x
Describe the bug
ASP.NET Core OData 7.x had a special class WebApiAssembliesResolver that used to access only assemblies available to the application. Now ASP.NET Core OData 8.x moved ModelBuilder to a separate assemby but looks like this class is missing and now replaced with:
services.TryAddSingleton<IAssemblyResolver, DefaultAssemblyResolver>();
Now this class is easy to implement:
public class WebApiAssembliesResolver : IAssemblyResolver
{
public IEnumerable<Assembly> Assemblies { get; }
/// <summary>
/// Initializes a new instance of the WebApiAssembliesResolver class.
/// </summary>
/// <param name="applicationPartManager">The inner manager.</param>
public WebApiAssembliesResolver(ApplicationPartManager applicationPartManager)
{
var parts = applicationPartManager.ApplicationParts;
Assemblies = parts
.OfType<AssemblyPart>()
.Select(p => p.Assembly)
.Distinct()
.ToList();
}
}
And provide to EDM builder (don't forget to add WebApiAssembliesResolver as singleton elsewhere):
return builder.AddOData((opt, serviceProvider) =>
{
var resolver = serviceProvider.GetRequiredService<IAssemblyResolver>();
var builder = new ODataConventionModelBuilder(resolver)
opt.AddRouteComponents("xapi/v1", builder.GetEdmModel(), services =>
{
});
});
On my relatively small project on my fast developer machine I managed to reduce model load time from 7 seconds (230 assemblies!) to 0.5 seconds (5 assemblies!). Am I doing something incorrect? Should this class be provided instead of DefaultAssemblyResolver how it was in OData 7.x ?
@habbes have you seen this in your performance investigations? Looks pretty massive at first glance although it might require a more elaborate project sample to reproduce the gains.
Scanning assemblies can be incredibly inefficient. This might be one of those areas where using a source generator could help immensely.
The performance bottleneck is this:
_allTypesWithDerivedTypeMapping = new Lazy<IDictionary<Type, Type[]>>(
() => BuildDerivedTypesMapping(assembliesResolver),
isThreadSafe: false);
I never used 7.x version but I believe original class WebApiAssembliesResolver was there to solve this issue.