webapi core [FromQuery] dto model ignoring [Required(AllowEmptyStrings = true)]

39 Views Asked by At

i have a controller endpoint with two parameters

  1. sent from body
  2. sent as a query string parameters with dtoModel

i using [FromQuery] for the second object ,becouse i cannot pass two object in the body

public class MyDTO
{

    [Required(AllowEmptyStrings = true), StringLength(50)]

    public string Details { get; set; }

    public int value{ get; set; }

}

api contoller:

   [HttpPost("getDetails")]
   public async Task<List<getDetailsResult>> getDetails(List<string> dbList, [FromQuery] MyDTO data) 
   {}

when i call the api from angular with empty string for "Details" fields it's sent to api as null, like: http://sitename.com/api/getDetails?Details=&value=100

the [Required(AllowEmptyStrings = true)] attribute is ignoring and it will return an error "The Details field is Required"

angular http post call:

  public getDetails(
    dbList: string[],
    details: string,
    value: number
  ) {
    let result;
    let params = new HttpParams();

    params = params.append("details", "");   

    params = params.append("value", 100);

    result = this.http.post("/api/getDetails", dbList, {
      params: params,
    });
    return result.toPromise().then((data: any) => {
      //console.log(data);
      return data;
    });
  }

i have two questions:

  1. how i can allow calling the api with Required attribute if the value is empty string? there is any way to replace null value to empty string ?
  2. why cannot pass an empty string in a url query string?
1

There are 1 best solutions below

0
Md Farid Uddin Kiron On

how i can allow calling the api with Required attribute if the value is empty string? there is any way to replace null value to empty string ?

Well according to your scenario and shared code snippet you have acually two options.

First of all using custom model validation and another option is ComponentModel.DataAnnotations

If you would like to use custome model validation in that scenario, you should refactor your code in following way: In this way, you would have more control on your model.

Model Validator:

public class EmptyStringModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        

        var model = new MyDTO();



        if (bindingContext.ValueProvider.GetValue("Details").FirstOrDefault() == null)
        {
            model.Details = string.Empty;
        }

        bindingContext.Result = ModelBindingResult.Success(model);
        return Task.CompletedTask;
    }
}

Model:

[ModelBinder(BinderType = typeof(EmptyStringModelBinder))]
public class MyDTO
{

    
    [StringLength(50)]

    public string Details { get; set; }

    public int value { get; set; }

}

Alternatively, you also could use of model annotations.

enter image description here

As you may know in .NET we have [DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "[Null]")] which convert the null value into empty string "" If this property is not set, null field values are displayed as empty strings (""). So you could modify your model as following:

public class MyDTO
{

    [DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText = "")]
    [StringLength(50)]

    public string Details { get; set; }

    public int value { get; set; }

}

Output:

enter image description here

enter image description here

Note: Please refer to this official document, if you would like to check more sample.