Lorenzo Soncini
Lorenzo Soncini

Reputation: 61

.NET 6.0 Web Api, Pass empty string as parameter value

I'm start work with .NET 6 Web API. I have write a very simple controller:

[Route("[controller]")]
[ApiController]
public class TestController : ControllerBase
{
  [HttpGet,Route("sample")]
  public IActionResult ReturnSample(string ParameterOne, string ParameterTwo)
  {
    [... do something ...]
  }
}

The problem is that all parameter are mandatory.

URL: https://<server>/test/sample?ParameterOne=Value&ParameterTwo=Value

Works fine, all OK

URL: https://<server>/test/sample?ParameterOne=Value&ParameterTwo=

ERROR:

{
  "type":"https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title":"One or more validation errors occurred.",
  "status":400,
  "traceId":"00-dc73d9983b53750d2073c48bec522c70-98fe251af1accccf00",
  "errors":{"ParameterTwo":["The ParameterTwo field is required."]}}

How can I allow an empty value as a valid value for parameter?

Thanks Lorenzo

Upvotes: 6

Views: 12757

Answers (3)

Tallons
Tallons

Reputation: 71

In C# 8, a Nullable Reference Type Feature was introduced, which helps identify when a type is null and aids in preventing NullExceptions. It essentially gives you CS8618 warnings throughout your code to let you know that you might want to consider changing reference types to be nullable. With that said, this also changes how the compiler interprets the C# code.

This compiler interpretation change requires you to set your optional reference type parameters for your controller endpoint to be nullable. In this case: string?.

This feature is said to be defaulted to disabled, but when I built a .Net 6 project it was enabled (maybe I accidentally clicked a checkbox that enabled it or something when I built the project).


With the Feature Enabled:

Declare the optional string parameters as nullable: string?

public class TestController : ControllerBase
{
  [HttpGet("sample")]
  public IActionResult ReturnSample(string ParameterOne, string? ParameterTwo, string? ParameterThree)
  {
    [... do something ...]
  }
}

This supports the following URLs:

- https://{domainName}/test/sample?ParameterOne=Value

- https://{domainName}/test/sample?ParameterOne=Value&ParameterTwo=Value

- https://{domainName}/test/sample?ParameterOne=Value&ParameterThree=Value

- https://{domainName}/test/sample?ParameterOne=Value&ParameterTwo=Value&ParameterThree=Value

- https://{domainName}/test/sample?ParameterThree=Value&ParameterOne=Value

NOTE: Notice that ParameterOne is in all of the above URLs, this is because it is required, due to NOT being a nullable string string?. In addition, notice that the query parameter order doesn't matter, the controller will map the query to your endpoint's parameter names (this is called Model Binding).

  • If you don't want the missing query parameters to be interpreted as null when the endpoint is hit, then you can set the string(s) to have default values. Remember when adding default values to a parameter it makes it optional and optional parameters must go at the end of the parameter list (or end of argument):
  [HttpGet("sample")]
  public IActionResult ReturnSample(string ParameterOne, string? ParameterTwo = "test2", string? ParameterThree = "test3")


With the Feature Disabled:

using System.ComponentModel.DataAnnotations;

public class TestController : ControllerBase
{
 [HttpGet("sample")]
  public IActionResult ReturnSample([Required] string ParameterOne, string ParameterTwo, string ParameterThree)
}

NOTE: Notice that the required parameter ParameterOne has the [Required] attribute associated with it. This will require that parameter when the endpoint is called. [Required] comes from the System.ComponentModel.DataAnnotations namespace and is a Validation Attribute. If you want all reference type parameters to be required use [FromQuery]

  • This endpoint will support the same URLs that are listed above in the Feature Enabled Section.

  • If you don't want the missing query parameters to be interpreted as null when the endpoint is hit, then you can set the string(s) to have default values. Remember when adding default values to a parameter it makes it optional and optional parameters must go at the end of the parameter list (or end of argument):

  [HttpGet("sample")]
  public IActionResult ReturnSample([Required] string ParameterOne, string ParameterTwo = "test2", string ParameterThree = "test3")

Enabling/Disable The Nullable Reference Type Feature

WARNING: Enabling/Disabling the Nullable Reference Type Feature will affect how your code is read by the compiler and may incur major side effects. If you are just starting a project, like me, then this change shouldn't affect anything.

  • Go to your .csproj file (double-click on your project)
  • Adjust <Nullable>disable</Nullable> to <Nullable>enable</Nullable> or vice versa.

Upvotes: 4

Nb777
Nb777

Reputation: 2032

If you don't want to send value at all, you can try using ?:

[HttpGet("{ParameterOne?}/{ParameterTwo?}"),Route("sample")]
public IActionResult ReturnSample(string ParameterOne = null, string ParameterTwo = null)
{
 [... do something ...]
}

Note: if you have two parameters and just one of them could have a value, then the second parameter that has value as null should be always in your uri in the end:

[HttpGet("{ParameterOne?}/{ParameterTwo}")] => wrong
[HttpGet("{ParameterTwo}/{ParameterOne?}")] => correct

Upvotes: 1

Guru Stron
Guru Stron

Reputation: 141600

You can set the default value for the second parameter:

[HttpGet,Route("sample")]
public IActionResult ReturnSample(string ParameterOne, string? ParameterTwo = null)
{
   // ...
}

Upvotes: 1

Related Questions