Retrieving the LoaderExceptions property of ReflectionTypeLoadException in ASP.NET Core

I recently had a ReflectionTypeLoadException in a Docker hosted ASP.NET Core application. The exception looks something like this:

System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.  
   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeAssembly.get_DefinedTypes()
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFeatureProvider.PopulateFeature(IEnumerable`1 parts, ControllerFeature feature)
   at Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartManager.PopulateFeature[TFeature](TFeature feature)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.GetControllerTypes()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.BuildModel()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.GetDescriptors()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.OnProvidersExecuting(ActionDescriptorProviderContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ActionDescriptorCollectionProvider.GetCollection()
   at Microsoft.AspNetCore.Mvc.Internal.ActionDescriptorCollectionProvider.get_ActionDescriptors()
   at Microsoft.AspNetCore.Mvc.Internal.AttributeRoute.GetTreeRouter()
   at Microsoft.AspNetCore.Mvc.Internal.AttributeRoute.RouteAsync(RouteContext context)
   at Microsoft.AspNetCore.Routing.RouteCollection.<RouteAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MyWebAssembly.ReflectionTypeLoadExceptionLoggingMiddleware.<Invoke>d__3.MoveNext() in /app/src/MyWeb/Startup.cs:line 245

For some strange reason I could not reproduce the exception on my local environment so I needed some way to log the contents of the LoaderException property. In this GitHub issue on the aspnet/Mvc repo i found some example code which I modified a bit. It is a Middleware that catches the ReflectionTypeLoadException, loops over its LoaderExceptions and logs them.

public class ReflectionTypeLoadExceptionLoggingMiddleware  
{
    private readonly RequestDelegate _next;
    private readonly Microsoft.Extensions.Logging.ILogger _logger;
    public ReflectionTypeLoadExceptionLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger<ReflectionTypeLoadExceptionLoggingMiddleware>();
    }
    public async Task Invoke(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            var reflectionTypeLoadException = ex as ReflectionTypeLoadException;
            if (reflectionTypeLoadException != null && reflectionTypeLoadException.LoaderExceptions != null)
            {
                _logger.LogError("ReflectionTypeLoadException {0}", ex);
                _logger.LogError("Loader exceptions messages: ");
                foreach (var exception in reflectionTypeLoadException.LoaderExceptions)
                {
                    _logger.LogError("ex {0}", exception);
                }
            }
            throw;
        }
    }
}

Insert it before app.UseMvc(); in the pipeline.

...
app.UseMiddleware<ReflectionTypeLoadExceptionLoggingMiddleware>();  
app.UseMvc();  
...

If you can reproduce the issue locally the ReflectionTypeLoadExceptionLoggingMiddleware is not needed because the error page shown when using the app.UseDeveloperExceptionPage(); middleware should unwrap these exceptions. See this GitHub issue and the fix.

The strange error I got was this:

System.TypeLoadException: Could not load type 'VisualStudioConfiguration.SetupConfigurationClass' from assembly 'MyWebAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.  

Could not find the root cause but updating all NuGet packages to the latest version solved the issue.

Update

See J3ffb's comment below where he points out the root cause (dependency on gulp-sass) and how to solve it. Thanks!

comments powered by Disqus