aspnetcore
aspnetcore copied to clipboard
Warning AD0001 : Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' NullReferenceException due to generics in minimal API
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the bug
AspNetCore Analyzer throws warning due to usage of generics in minimal API:
1>CSC: Warning AD0001 : Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.Route HandlerAnalyzer' threw an exception of type 'System.NullReferenceException' with message 'Object reference not set to an instance of an object.'.
Expected Behavior
This all works fine when running it, the analyzer is just not pleased with the usage of generics. Switching TEndpointInput to a concrete type such as DummyEndpointInput of course also make the warning disappear.
Steps To Reproduce
https://github.com/madskonradsen/minimal-reproducibles/tree/main/dotnet-analyzer-warning-minimalapi-generics/MinimalAPIGenericsWarning
Or simply:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
static void UseEndpoint<TEndpointInput>(WebApplication app) where TEndpointInput : class
{
app.MapPost("/test", (TEndpointInput data) => Results.Ok(data));
}
UseEndpoint<DummyEndpointInput>(app);
app.Run();
public class DummyEndpointInput
{
}
Exceptions (if any)
No response
.NET Version
8.0.303
Anything else?
No response
@madskonradsen Thanks for reporting this issue! I resolved the stack trace for this and it looks like the DisallowNonParsableComplexTypesOnParameters analyzer is throwing this particular error.
at Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer.<DisallowNonParsableComplexTypesOnParameters>g__ResovleParameterTypeSymbol|8_2(IParameterSymbol parameterSymbol)
I suspect the issue is in this chunk of code, which doesn't handle the fact that the type associated with TEndpointInput might not have passed the INamedTypeSymbol check.
https://github.com/dotnet/aspnetcore/blob/e31445e897e416b743f436b27cb81f3c87c56d27/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/DisallowNonParsableComplexTypesOnParameters.cs#L125-L131
Would you be interested in opening a PR with a fix for this? I'm happy to provide guidance on how to test/fix this.
Sure! Seems like a nice small task :)
@madskonradsen Great! You can check out the build from source document for instructions on how to set up the repo for local development. You might run into issues here since our repo does unique things (relies on a nightly build of the .NET SDK, builds IIS if you're on Windows, etc) but I can hopefully get it working with any issues that you run into here.
After that, you can copy the code from your repro into a new test case in this file and that should get you setup to be able to debug and apply a fix.
@captainsafia Sooo getting the environment up and running was pretty breezy. Roslyn analyzers on the other hand. But they are still fun to work with :) I feel like I've gone in the wrong direction: https://github.com/dotnet/aspnetcore/compare/main...madskonradsen:aspnetcore:mads/56831
I would have expected methodSymbol.TypeParameters to not be empty, but seems like I'm missing something. Any pointers? :)
@madskonradsen Yes, I believe the issue here is the fact that methodSymbol actually refers to the lambda expression based as an argument to the MapPost call ( (TEndpointInput data) => Results.Ok(data)) which has no type parameters itself but has a parameter that is a type parameter.
I believe what you might actually want to do here is iterate through methodSymbol.Parameters and check if the SymbolKind associated with each parameters is a TypeParameter.
This has annoyed me more-or-less ever since .Net 8 launched, but never understood what causes it to happen nor found any issues on it, so I just ignored the warning and went on with my life. Good to see it's not just me experiencing this. Generic handlers would be a logical denominator. Quite niche after all.
Take 2: https://github.com/dotnet/aspnetcore/compare/main...madskonradsen:aspnetcore:mads/56831-2
This is not finished, but it just feels like the wrong direction to go in, but based on the current API, I'm having a hard time seeing other ways around it, and how I should be able to achieve it by just looking at the Parameters. The code above passes 2/3 tests so far. But I just can't shake the feeling that there must be a better way.
@captainsafia
Any progress on this? The warning still exists in dotnet cli 9.0.100. It doesn't seem to appear when building in Visual Studio 17.12 though.
I haven't had much luck with the patch apart from the code above, and haven't heard any feedback from the dotnet team.
I found a workaround by creating a wrapper and using AsParameters attribute. Here is an example with both route parameter and body.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
static void UseEndpoint<TContent, TRouteParameter>(WebApplication app) where TContent : class
{
app.MapPost("/test/{id}", ([AsParameters] EndpointParameters<TContent, TRouteParameter> parameters) => Results.Ok(parameters.Data));
}
UseEndpoint<DummyEndpointInput, int>(app);
app.Run();
public class DummyEndpointInput;
public struct EndpointParameters<TEndpointInput, TRouteParameter>
{
public TEndpointInput Data { get; init; }
public TRouteParameter Id { get; init; }
}
For route parameters, you may also want to add where TRouteParameter : IParsable<TRouteParameter> constraint.
I also think it's worth mentioning in this thread that there is a feature flag called debug-analyzers that can be used like so:
dotnet build -c Release -p:Features="debug-analyzers"
(The flag somehow only consistently work when using Release configuration.)
To close the loop on this, @benhopkinstech recently investigated the root cause for this and contributed a fix that should be released in .NET 10 Preview 3.
The PR with the fix is included in https://github.com/dotnet/aspnetcore/pull/60742.
@benhopkinstech Given the number of upvotes on this issue and the relative simplicity of the fix, we should consider back porting it to .NET 8 and 9 once we've verified that everything works when .NET 10 Preview 3 goes out.
Now that .NET 10 Preview 3 is out, is anyone able to verify that the issue is resolved for them in that version? That would help us with the back port decision.
@captainsafia
As discussed within #60719 this is still only resolved when running dotnet build using the new official .NET 10 Preview 3 SDK.
If we run a rebuild in the latest vs version, which is still 17.14.0 Preview 2.0 (same as when we originally discussed) the issue is still there.
I am still waiting for the latest preview version of vs to confirm it is resolved there 😊
@captainsafia here's a fresh stack trace on preview 3, doesn't look too good (although it's throwing #60719 type warning, should that be reopened?):
dotnet build c:\Users\erwin\bank-api\BankApi.sln --no-incremental /property:GenerateFullPaths=true /consoleloggerparameters:NoSummary /p:Configuration=Debug /p:Platform="Any CPU"
Determining projects to restore...
Restored C:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj (in 580 ms).
Restored c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj (in 580 ms).
Restored c:\Users\erwin\bank-api\BankApi.Tests\BankApi.Tests.csproj (in 580 ms).
Restored c:\Users\erwin\bank-api\BankApi.Orchestration\BankApi.Orchestration.csproj (in 580 ms).
Restored C:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj (in 580 ms).
C:\Program Files\dotnet\sdk\10.0.100-preview.3.25201.16\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(326,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
C:\Program Files\dotnet\sdk\10.0.100-preview.3.25201.16\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(326,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [c:\Users\erwin\bank-api\BankApi.Tests\BankApi.Tests.csproj]
C:\Program Files\dotnet\sdk\10.0.100-preview.3.25201.16\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(326,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
C:\Program Files\dotnet\sdk\10.0.100-preview.3.25201.16\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(326,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [c:\Users\erwin\bank-api\BankApi.Orchestration\BankApi.Orchestration.csproj]
C:\Program Files\dotnet\sdk\10.0.100-preview.3.25201.16\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(326,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Helper.KiotaServiceCollectionExtensions.cs(23,29): warning CS0618: 'KiotaClientFactory.GetDefaultHandlerTypes()' is obsolete: 'Use GetDefaultHandlerActivatableTypes instead' [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.DocInfo.cs(8,32): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Helper.KiotaServiceCollectionExtensions.cs(45,29): warning CS0618: 'KiotaClientFactory.GetDefaultHandlerTypes()' is obsolete: 'Use GetDefaultHandlerActivatableTypes instead' [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.Operation.cs(17,9): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.Operation.cs(26,34): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.SecurityScheme.cs(64,17): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.SecurityScheme.cs(64,17): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.SecurityScheme.cs(65,17): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.ComponentResponses.cs(72,34): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.ComponentResponses.cs(72,34): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
c:\Users\erwin\bank-api\BankApi.Core\Defaults\Transformer.Operation.cs(55,9): warning CS8602: Dereference of a possibly null reference. [c:\Users\erwin\bank-api\BankApi.Core\BankApi.Core.csproj]
BankApi.Core -> c:\Users\erwin\bank-api\BankApi.Core\bin\Debug\net10.0\BankApi.Core.dll
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Beta\BankApi.Service.Beta.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Analyzers.RouteHandlers.RouteHandlerAnalyzer' threw an exception of type 'System.IndexOutOfRangeException' with message 'Index was outside the bounds of the array.'. [c:\Users\erwin\bank-api\BankApi.Service.Stable\BankApi.Service.Stable.csproj]
BankApi.Tests -> c:\Users\erwin\bank-api\BankApi.Tests\bin\Debug\net10.0\BankApi.Tests.dll
BankApi.Service.Stable -> C:\Users\erwin\bank-api\BankApi.Service.Stable\bin\Debug\net10.0\BankApi.Service.Stable.dll
BankApi.Service.Beta -> C:\Users\erwin\bank-api\BankApi.Service.Beta\bin\Debug\net10.0\BankApi.Service.Beta.dll
GenerateOpenApiDocuments:
GenerateOpenApiDocuments:
dotnet "C:\Users\erwin\.nuget\packages\microsoft.extensions.apidescription.server\10.0.0-preview.3.25172.1\build\../tools/dotnet-getdocument.dll" --assembly "C:\Users\erwin\bank-api\BankApi.Service.Stable\bin\Debug\net10.0\BankApi.Service.Stable.dll" --file-list "obj\BankApi.Service.Stable.OpenApiFiles.cache" --framework ".NETCoreApp,Version=v10.0" --output "c:\Users\erwin\bank-api\Specs.Generated" --project "BankApi.Service.Stable" --assets-file "C:\Users\erwin\bank-api\BankApi.Service.Stable\obj\project.assets.json" --platform "AnyCPU" --file-name openapi_v1
dotnet "C:\Users\erwin\.nuget\packages\microsoft.extensions.apidescription.server\10.0.0-preview.3.25172.1\build\../tools/dotnet-getdocument.dll" --assembly "C:\Users\erwin\bank-api\BankApi.Service.Beta\bin\Debug\net10.0\BankApi.Service.Beta.dll" --file-list "obj\BankApi.Service.Beta.OpenApiFiles.cache" --framework ".NETCoreApp,Version=v10.0" --output "c:\Users\erwin\bank-api\Specs.Generated" --project "BankApi.Service.Beta" --assets-file "C:\Users\erwin\bank-api\BankApi.Service.Beta\obj\project.assets.json" --platform "AnyCPU" --file-name openapi
info: Microsoft.EntityFrameworkCore.Update[30100]
info: Microsoft.EntityFrameworkCore.Update[30100]
Saved 0 entities to in-memory store.
Saved 0 entities to in-memory store.
info: Microsoft.EntityFrameworkCore.Update[30100]
Saved 2 entities to in-memory store.
info: Microsoft.EntityFrameworkCore.Update[30100]
Saved 2 entities to in-memory store.
Generating document named 'v2'.
Using discovered `GenerateAsync` overload with version parameter.
Generating document named 'v1'.
Using discovered `GenerateAsync` overload with version parameter.
Writing document named 'v1' to 'c:\Users\erwin\bank-api\Specs.Generated\openapi_v1.json'.
Writing document named 'v2' to 'c:\Users\erwin\bank-api\Specs.Generated\openapi_v2.json'.
BankApi.Orchestration -> c:\Users\erwin\bank-api\BankApi.Orchestration\bin\Debug\net10.0\BankApi.Orchestration.dll
BTW i had to keep Microsoft.AspNetCore.OpenApi on the preview 1 version because 2 and 3 failed to build, (see #61457) so i used following:
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-preview.1.25120.3" />
Still an issue on preview 5 by the way
This issue is persistent and its hard to track down the exact root cause because various incantations of syntax can trigger it.
Conclusion: we'll add a top-level try/catch to the analyzer to avoid unhandled exceptions leaking out to the compiler/Visual Studio.
Conclusion: we'll add a top-level try/catch to the analyzer to avoid unhandled exceptions leaking out to the compiler/Visual Studio.
I followed up on this. It's not recommended to add top-level try/catch in analyzer code. The right thing to do is let the uncaught excpetions through and have them surface via the AD0001 diagnostic that gets emitted here.
It's possible that there are multiple scenarios that cause this issue so we'd have to root cause each one independently and implement the correct bug fix for them.
The exceptions shouldn't cause any breaks in the build so they're largely an annoyance (and possibly need to be exempted if warnings as errors is on).
Given these things and the fact that RC1 code complete is fast approaching, we'll have to move this to the backlog. :/
To properly address this, we'll need to identify specific repro cases and see if we can apply patches for them in the implementation.