ValidationsGenerator silently skips endpoint handlers passed as delegate variables or parameters
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Summary
The `ValidationsGenerator` performs validation discovery by resolving the endpoint handler method at `Map*` call sites. The resolver, `ResolveMethodFromOperation` in [`InvocationOperationExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/InvocationOperationExtensions.cs) (shared source, linked into `Microsoft.Extensions.Validation.ValidationsGenerator.csproj`), handles inline lambdas (`IAnonymousFunctionOperation`), local functions, method groups, and readonly fields — but has no case for `IParameterReferenceOperation` or `ILocalReferenceOperation`. A handler passed as a delegate **variable or method parameter** falls through to `_ => null`.
For the RequestDelegateGenerator this is benign (it falls back to the runtime `RequestDelegateFactory`). For the **ValidationsGenerator** it is not: `TryGetRouteHandlerMethod` returns `false`, `ExtractValidatableTypes` (`ValidationsGenerator.TypesParser.cs`) gets an empty parameter list, and validation discovery for that endpoint is **silently skipped** — no diagnostic, no generated `ValidatableInfo`, validation just doesn't run.
This affects even completely non-generic handlers.
## Reproduction
```csharp
public static class EndpointExtensions
{
// Handler arrives as a delegate parameter — never resolved by the generator
public static RouteHandlerBuilder MapCommand(
this IEndpointRouteBuilder endpoints,
string pattern,
Func> handler)
where TRequest : IValidatable
=> endpoints.MapPost(pattern, handler);
}
// Non-generic variant is equally affected:
Func> handler = async req => Results.Ok();
app.MapPost("/orders", handler); // validation silently skipped
```
## Expected Behavior
Either the parameter types are discovered (the ValidationsGenerator only needs the delegate's parameter *types*, not the method body — when method resolution fails, the delegate type's `Invoke` signature is sufficient for `TryExtractValidatableType`), or the generator emits a diagnostic that the handler could not be statically analyzed.
## Actual Behavior
Validation discovery is silently skipped for the endpoint.
## Notes
Discovered while investigating #65418 / #65419. The repro in #65418 used this delegate-parameter shape; #65419 fixes the `ITypeParameterSymbol` handling layer (constraint walking + `typeof(T)` leak into generated code) and is kept scoped to that per review feedback, so the resolver gap is tracked separately here. A fix likely belongs on the Validation generator's side (fallback to the delegate type's `Invoke` signature) rather than in the shared RDG resolver, to avoid changing RDG behavior.
Contributor guide
Assessment
This issue has not been assessed yet.