Friday, June 20, 2025
HomeC#The Delegate RequestDelegate doesn't take X arguments – Experiences with minimal APIs...

The Delegate RequestDelegate doesn’t take X arguments – Experiences with minimal APIs – blogs.cninnovation.com


When working with .NET minimal APIs, the endpoint definition may be improved by utilizing TypedResults for higher OpenAPI documentation. Nevertheless, this seemingly easy change can result in complicated compiler errors, similar to “Delegate RequestDelegate doesn’t take X arguments.” Even the GitHub Copilot coding agent struggled to resolve these points routinely.

On this article, we’ll discover why this error happens, what it means in your API design, and easy methods to resolve it utilizing the generic Outcomes kind.

Copilot coding agent outcomes

After GitHub Copilot coding agent created an API for me, with a pull request evaluate I requested to:

  • With the minimal APIs within the EduValidate.Apiservice mission, create an endpoints-class and transfer the minimal APIs code from Program.cs to this file.
  • With minimal APIs, use TypedResults as an alternative of Outcomes

Copilot succeeded doing the primary process, however failed with the second:

✅ Created endpoints class – Moved minimal API code from Program.cs to Endpoints/CodeAnalysisEndpoints.cs

⚠️ TypedResults situation – Found that changing Outcomes with TypedResults causes compilation errors (“Delegate RequestDelegate doesn’t take X arguments”). This seems to be a kind inference situation within the minimal API processing. The endpoints work accurately with Outcomes for now.

I had some extra duties to repair, and Copilot fastened all of them except this one. Many builders encounter this error. Let’s look at why it occurs and easy methods to resolve it.

Utilizing Outcomes

A minimal APIs code utilizing the Outcomes class to return outcomes can appear like this:

app.MapGet("/api/submission/{submissionId}/evaluation", async (
  string submissionId,
  EduValidateDbContext dbContext,
  CancellationToken cancellationToken) =>
{
  // some code

  if (submission == null)
  {
    return Outcomes.NotFound($"Submission {submissionId} not discovered");
  }

  // some code
  return Outcomes.Okay(analysisResult);
})
.WithName("GetAnalysis")
.WithSummary("Get evaluation outcomes for a submission");

In case there’s simply just one doable end result kind, the Outcomes class can simply get replaced with a TypedResults, however with two or extra occurrences, this code now not compiles:

app.MapGet("/api/submission/{submissionId}/evaluation", async (
  string submissionId,
  EduValidateDbContext dbContext,
  CancellationToken cancellationToken) =>
{
  // some code

  if (submission == null)
  {
    return TypedResults.NotFound($"Submission {submissionId} not discovered");
  }

  // some code
  return TypedResults.Okay(analysisResult);
})
.WithName("GetAnalysis")
.WithSummary("Get evaluation outcomes for a submission");

The compiler complains with Delegate RequestDelegate doesn’t take 3 arguments.

Why utilizing TypedResults in any respect? When utilizing TypedResults, the knowledge what may be returned from the API is added to the OpenAPI doc, with out the necessity to add attributes for each end result kind.

What’s the rationale for this error?

Why does the RequestDelegate overload match?

The strategy MapGet is specified with two overloads.

One is the one we want to use when passing an expression. This methodology has been added for minimal APIs:

[RequiresDynamicCode("This API may perform reflection on the supplied delegate and its parameters. These types may require generated code and aren't compatible with native AOT applications.")]
[RequiresUnreferencedCode("This API may perform reflection on the supplied delegate and its parameters. These types may be trimmed if not directly referenced.")]
public static RouteHandlerBuilder MapGet(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string sample, Delegate handler);

This overload existed earlier than minimal APIs have been accessible. This methodology receives a RequestDelegate parameter:

public static IEndpointConventionBuilder MapGet(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string sample, RequestDelegate requestDelegate);

The compiler now assumes to make use of this overload as an alternative of the earlier one. Nevertheless, this overload wants a match with parameters and the return kind for the RequestDelegate delegate kind. This definition returns a Job, and may solely use a HttpContext as parameter.

public delegate Job RequestDelegate(HttpContext context);

When enabling to make use of the RequestDelegateGenerator (which is used with native AOT, or specifying EnableRequestDelegateGenerator within the mission file), the supply generator replaces the tactic with the Delegate parameter to make use of the tactic with the RequestDelegate parameter as an alternative, which permits minimal APIs with native AOT.

Utilizing a lambda expression, the compiler checks for all ´returnstatements throughout the methodology to resolve the end result kind. The strategies of theOutcomesclass returnIResult. Nevertheless, TypedResults.Okay<T>returnsOkay<T>, and TypedResults.NotFound<string>returnsNotFound<string>. Because the compiler can not resolve the end result kind immediately, the RequestDelegate` overload is used, which doesn’t match the variety of parameters.

All these return sorts implement the interface IResult. Thus altering the return kind to Job<IResult> helps compiling:

app.MapGet("/api/submission/{submissionId}/evaluation", async Job<IResult> (
  string submissionId,
  EduValidateDbContext dbContext,
  CancellationToken cancellationToken) =>
{
  // some code

  if (submission == null)
  {
    return TypedResults.NotFound($"Submission {submissionId} not discovered");
  }

  // some code
  return TypedResults.Okay(analysisResult);
})
.WithName("GetAnalysis")
.WithSummary("Get evaluation outcomes for a submission");

Nevertheless, this isn’t the repair wanted so as to add the end result data to the OpenAPI description.

The repair

This may be fastened by utilizing the generic Outcomes kind which permits utilizing 2, 3, 4, or extra generic parameters sorts, and specifying the end result sorts:

app.MapGet("/api/submission/{submissionId}/evaluation", async Job<Outcomes<Okay<CodeAnalysisResult>, NotFound<string>>> (
  string submissionId,
  EduValidateDbContext dbContext,
  ILogger<ICodeAnalysisService> logger,
  CancellationToken cancellationToken) =>
{

The outcomes returned is both Okay<CodeAnalysisResult>, or NotFound<string>, wrapped right into a Job.

With this alteration, the knowledge on the return values goes to the OpenAPI description.

The Copilot coding agent is enhanced constantly. It’s additionally doable to attach him to be taught from my very own repositories, the place I’m certain he would have resolved the difficulty routinely. Perhaps he additionally learns from studying this text 🙂

Abstract

In abstract, when constructing minimal APIs, utilizing the generic Outcomes kind with particular end result sorts not solely resolves complicated compiler errors but in addition improves your OpenAPI documentation. This strategy ensures your endpoints are each sturdy and well-documented.

For extra data:

Creating APIs is roofed in Chapter 2 of my ebook:

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments