dotnet / dotnet/aspnetcore

ValidationsGenerator silently skips endpoint handlers passed as delegate variables or parameters

Open
#67,122 2 comments 1 reaction 1 assignee Claimed by @Youssef1313 View on GitHub
area-minimal feature-validation
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.