Announcements icon indicating copy to clipboard operation
Announcements copied to clipboard

[Breaking change]: TryParse and BindAsync discovery on Map* parameters will throw for invalid methods

Open BrennanConroy opened this issue 2 years ago • 0 comments

Description

Starting in RC2, when we look for TryParse or BindAsync methods on your parameter types if we don't find a valid one we will also look for invalid ones and throw at startup to let you know that you might have written your method signature incorrectly to avoid unexpected behavior.

Version

.NET 6 RC2

Previous behavior

// Todo.TryParse is not in a valid format, will try to bind from body as json instead
app.MapPost("/endpoint", (Todo todo) => todo.Item);

public class Todo
{
    public string Item { get; set; }

    public static bool TryParse(string value) => true;
}

New behavior

We have now changed it so that if we see a public TryParse or BindAsync that doesn't match the expected syntax we will throw on startup. The above example would throw an error similar to:

TryParse method found on Todo with incorrect format. Must be a static method with format
bool TryParse(string, IFormatProvider, out Todo)
bool TryParse(string, out Todo)
but found
Boolean TryParse(System.String)

Type of breaking change

  • [X] Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load/execute or different run-time behavior.
  • [x] Source incompatible: Source code may encounter a breaking change in behavior when targeting the new runtime/component/SDK, such as compile errors or different run-time behavior.

Reason for change

This change was made so that developers would be aware when they wrote a BindAsync or TryParse method that it wasn't in a valid format. Otherwise the framework would fallback to assuming the parameter is json from the body and could result in unexpected behavior.

Recommended action

It is possible your types have a BindAsync or TryParse with different syntax for other reasons besides parameter binding and will now throw at startup. There are multiple options to avoid this behavior:

  • Make your BindAsync or TryParse method internal or private
  • Add a new BindAsync or TryParse method that is in the syntax we are looking for (we ignore invalid methods if we find a valid one)
  • Mark your parameter as [FromBody]

Affected APIs

All IEndpointRouteBuilder.Map*(...) methods are affected by this change, e.g. app.MapGet(...) and app.MapPost(...). And RequestDelegateFactory.Create(...)

Discussion issue: https://github.com/dotnet/aspnetcore/issues/36810

BrennanConroy avatar Sep 21 '21 17:09 BrennanConroy