Logo

dev-resources.site

for different kinds of informations.

[KOSD] Change of FromQuery Model Binding from .NET 6 to .NET8

Published at
11/3/2024
Categories
aspnet
c
core
experience
Author
gohchunlin
Categories
4 categories in total
aspnet
open
c
open
core
open
experience
open
Author
10 person written this
gohchunlin
open
[KOSD] Change of FromQuery Model Binding from .NET 6 to .NET8

Recently, while migrating our project from .NET 6 to .NET 8, my teammate Jeremy Chan uncovered an undocumented change in model binding behaviour that seems to appear since .NET 7. This change is not clearly explained in the official .NET documentation, so it can be something developers easily overlook.

To illustrate the issue, let’s begin with a simple Web API project and explore a straightforward controller method that highlights the change.

[ApiController]
public class FooController
{
  [HttpGet()]
  public async void Get([FromQuery] string value = "Hello")
  {
    Console.WriteLine($"Value is {value}");

    return new JsonResult() { StatusCode = StatusCodes.Status200OK };
  }
}
Enter fullscreen mode Exit fullscreen mode

Then we assume that we have nullable enabled in both .NET 6 and .NET 8 projects.

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <Nullable>enable</Nullable>
        ...
    </PropertyGroup>

    ...

</Project>
Enter fullscreen mode Exit fullscreen mode

Situation in .NET 6

In .NET 6, when we call the endpoint with /foo?value=, we shall receive the following error.

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-5bc66c755994b2bba7c9d2337c1e5bc4-e116fa61d942199b-00",
  "errors": {
    "value": [
      "The value field is required."
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

However, if we change the method to be as follows, the error will not be there.

public async void Get([FromQuery] string? value)
{
    if (value is null)
        Console.WriteLine($"Value is null!!!");
    else
        Console.WriteLine($"Value is {value}");

    return new JsonResult() { StatusCode = StatusCodes.Status200OK };
}
Enter fullscreen mode Exit fullscreen mode

The log when calling the endpoint with /foo?value= will then be “Value is null!!!”.

Hence, we can know that query string without value will be interpreted as being null. That is why there will be a validation error when value is not nullable.

Thus, we can say that, in order to make the endpoint work in .NET 6, we need to change it to be as follows to make the value optional. This will not mark value as a required field.

public async void Get([FromQuery] string? value = "Hello")
Enter fullscreen mode Exit fullscreen mode

Now, if we call the endpoint with /foo?value=, we shall receive see the log “Value is Hello” printed.

Situation in .NET 8 (and .NET 7)

Then how about in .NET 8 with the same original setup, i.e. as shown below.

public async void Get([FromQuery] string value = "Hello")
Enter fullscreen mode Exit fullscreen mode

In .NET 8, when we call the endpoint with /foo?value=, we shall see the log “Value is Hello” printed.

So, what is happening here?

In .NET 7, a new Interface IParsable was introduced. Thus, starting from the .NET 7, IParsable.TryParse API is used for binding controller action parameter values.

Initial research shows that, under the hood, .NET 7 onwards, the new model binding implementation is used and it causes this to happen.

References

KOSD, or Kopi-O Siew Dai, is a type of Singapore coffee that I enjoy. It is basically a cup of coffee with a little bit of sugar. This series is meant to blog about technical knowledge that I gained while having a small cup of Kopi-O Siew Dai.

experience Article's
30 articles in total
Favicon
One Year with GitHub Copilot: Reflections, Lessons, and Insights
Favicon
Our experience becoming a Compose-first app
Favicon
Manifesting Milestones: My Transformative Journey Through 2024
Favicon
What great leaders don't do after you resign
Favicon
AnatomĂ­a de un Layoff: del rumor al paro
Favicon
[KOSD] Change of FromQuery Model Binding from .NET 6 to .NET8
Favicon
The 5 Stages of Grief in Tech Layoffs - a story
Favicon
AI takeover?
Favicon
From Legacy to .NET 8: Migrating with NDepend
Favicon
Kaizen: My Journey to be Azure Developer Associate
Favicon
[KOSD] Multiple Parallel Operations in Entity Framework Core (.NET 8)
Favicon
Finding Strength in Code: Navigating Emotional Overwhelm as a Software Engineer
Favicon
The Future of Website Building: AI-Powered Solutions for Easier, Smarter, and More Personalized Websites
Favicon
Pushing Pkl Content from GitHub to AWS S3
Favicon
Learning Postman Flows and Newman: A Beginner’s Journey
Favicon
Processing S3 Data before Returning It with Object Lambda (version 2024)
Favicon
Setting up Custom Domain for AWS API Gateway (version 2024)
Favicon
The experience is next-level
Favicon
We have to talk about Dev
Favicon
Why Data is Important for Enhancing Customer Experience?
Favicon
Java celebrates its 29th birthday
Favicon
Gaps in SOC Operator and Analyst Skillsets
Favicon
Explore My Top 7 Favorite Spots in Sydney with Me
Favicon
Elevating Your Business with Personalized Experiences
Favicon
Setup and Access Private RDS Database via a Bastion Host
Favicon
What I learnt after working in startups?
Favicon
The role of iterating
Favicon
From Fan to Organizer: My Incredible Journey with Mautic Conference India
Favicon
Migrate to TLS 1.2 for Azure Blob Storage
Favicon
The role of tests

Featured ones: