ApiDescriptionGroupCollectionProvider fails for controllers with parameter type Exception
Description of the bug
If a controller method uses a parameter of type System.Exception, accessing Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionGroupCollectionProvider.ApiDescriptionGroups allocates GBs of memory and seems to be in an infinite loop.
The same happens, if not the controller parameter itself, but one of its direct or nested properties is of type System.Exception.
To Reproduce
Write a controller with an action that takes a System.Exception as parameter:
[Route("[controller]/[action]")]
[ApiExplorerSettings(IgnoreApi = false, GroupName = nameof(TroublesController))]
public class TroublesController : Controller
{
public IActionResult TroublesMethod(Exception parameter)
{
return View();
}
}
Write a controller that displays a view to show the API description:
public class HomeController : Controller
{
public IActionResult Index(
[FromServices] IApiDescriptionGroupCollectionProvider apiExplorer)
=> View(apiExplorer);
}
In the view that should display the API, access the ApiDescriptionGroups:
@using Microsoft.AspNetCore.Mvc.ApiExplorer;
@model IApiDescriptionGroupCollectionProvider
// This will not return and consume lots of memory
@Model.ApiDescriptionGroups.Version
Further technical details
ASP.NET Core Version:
ASP.NET Core 3.1
Output of dotnet --info:
.NET Core SDK (reflecting any global.json): Version: 3.1.101 Commit: b377529961
Runtime Environment: OS Name: Windows OS Version: 10.0.17763 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\3.1.101\
Host (useful for support): Version: 3.1.1 Commit: a1388f194c
.NET Core SDKs installed: 2.1.802 [C:\Program Files\dotnet\sdk] 3.1.101 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed: Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
To install additional .NET Core runtimes or SDKs: https://aka.ms/dotnet-download
IDE:
Microsoft Visual Studio Professional 2019 Version 16.4.5
Thanks for contacting us.
It's not clear what you're trying to do. Do you intend to expose an API which accepts an Exception type? If not, you can apply the [NonAction] attribute on that method.
Whether or not it's a mistake, this sounds like an infinite loop in the API explorer code. These kinds of bugs are really hard for users to understand the cause of.
I don't know, why my initial response by eMail did not show up here. I paste it instead:
Thank you for your hint about the NonAction attribute. In my specific case the API accepts a type that contains a property of a type that again has a property of type Exception. But I already analyzed, that this has the same effect as using the Exception type directly in the API. So I simplified the example, which may indeed look a little bit weird now.
Thanks for the details, @gkeongit. I understand it's easy in some cases to add a property on a model and expect it to be available to the server/client, but it's not optimal unless you control the serialization yourself.
@mkArtakMSFT, maybe you are right about best practices for controller models. But the issue is more about some invalid behavior in the API explorer.
If the API explorer cannot handle certain kind of models (like those with an Exception as property type), it could propagate this by e.g. throwing a NotSupportedException. But it must not go into something, that looks like an endless loop eating up all available memory resources.
@gkeongit I agree with you completely. This is definitely not the desired behavior. The only argument I'm making here is that this is pretty corner-case scenario, given the approach is uncommon. Because of that I've moved it to Backlog to see how many people are impacted with this. If it turns out that many are impacted, we'll prioritize this investigation. For now, I just recommend changing your model to avoid this pattern.
OK, I can't change that model, so I will have to go without the API Explorer then.