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.

core Article's
30 articles in total
Favicon
Understanding Process Management in Operating Systems
Favicon
Introduction to Operating Systems
Favicon
What is SignalR? A Real-Time Communication Framework for .NET
Favicon
[KOSD] Change of FromQuery Model Binding from .NET 6 to .NET8
Favicon
JDK, JVM, and JRE: The Three Musketeers of Java Development 🏇
Favicon
Optimizing Your Development Machine: How Many Cores and Threads Do You Need for Programming?
Favicon
ASP .NET Core Best Practices
Favicon
Build Scalable Blazor CRUD Apps in 30 Minutes with Azure SQL
Favicon
The Benefits of Having More Threads than Cores: Unlocking the Power of Multi-threading in Modern Computing
Favicon
Deep Dive ASP.NET Core Middleware : Part 1
Favicon
The Purpose of Computer Processors (CPUs) and How Multiple Cores Improve Speed and Performance
Favicon
Primitive Data Types in Java
Favicon
How I Build a Scratch Proxy Server Using Node.js
Favicon
Javascript Working Mechanism
Favicon
A Journey Into the World of Programming with First Core Java Program
Favicon
[KOSD] Learning from Issues: Troubleshooting Containerisation for .NET Worker Service
Favicon
CORE WEB VITAL ISSUE
Favicon
Migrate to TLS 1.2 for Azure Blob Storage
Favicon
Keyboard input in Node.js
Favicon
Criando sua primeira aplicação console em .net
Favicon
Enabling CORS in a .NET Core Server-Side Application
Favicon
Digital Image Processing Notes
Favicon
Top Benefits of Using Core App Dashboard
Favicon
Understanding JavaScript Execution Context — The Key to Efficient Code
Favicon
5 Interesting Things About Strings in Java
Favicon
🔒 Introducing Serial Log and Metro Log: Simplifying Your Logging Experience In .NET MAUI! 📝🚇
Favicon
Understanding Core.js and Zone.js: Key to JavaScript Libraries
Favicon
Apitable.com Net6 Rest Api
Favicon
Custom resolve handler in Microsoft's ServiceProvider (enabling property injection)
Favicon
ASP.NET CORE REACT APP: System.InvalidOperationException: SPA default page middleware failed to return default page /index.html

Featured ones: