Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebApiAssembliesResolver class missing causing slow model build #1207

Open
sherlock1982 opened this issue Apr 8, 2024 · 2 comments
Open
Labels
bug Something isn't working

Comments

@sherlock1982
Copy link

sherlock1982 commented Apr 8, 2024

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 ?

@sherlock1982 sherlock1982 added the bug Something isn't working label Apr 8, 2024
@julealgon
Copy link
Contributor

@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.

@sherlock1982
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants