简体   繁体   中英

ASP.NET Core WebAPI FromBody attribute is not validating object non-reference fields

I have action Create inside my controller:

[HttpPost]
public async Task<IActionResult> Create([FromBody] PostCreate createDto)
{
    // do something with Create DTO
}

It accepts DTO for Post creation (parameter is marked with [FromBody] attribute). That DTO has 2 properties: string(reference type) Content property and System.Guid(value type) property:

public class PostCreate
{
    [Required(ErrorMessage = "content is required")]
    public string Content { get; set; }

    [Required(ErrorMessage = "blog id is required")]
    public Guid BlogId { get; set; }
}

The issue is that when i sending valid object everything is work just fine (both Content and BlodId properties are initialized). But when i sending empty object it checking only Content property:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|dfcd1687-4a0b9320d8411509.",
    "errors": {
        "Content": [
            "content is required"
        ]
    }
}

If i provide value only for Content property it passes validation and BlogId value is "00000000-0000-0000-0000-000000000000" or Guid.Empty. The same thing for all non reference types (eg for int value is 0).

Question 1: "Why it behaves like this?" Question 2: "How to make default validation check non-reference types for emptiness?"

UPDATE (useful walkaround) :

As Octavio Armenta pointed out in the answer : "You will probably have to create a custom attribute that checks the emptiness of a Guid. If you want to use an attribute.". I did it like this:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public class NotEmptyAttribute : ValidationAttribute
{
    public const string DefaultErrorMessage = "The {0} field must not be empty";

    public NotEmptyAttribute()
        : base(DefaultErrorMessage) { }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return true;
        }

        return value switch
        {
            Guid guid => guid != Guid.Empty,
            // other non-reference types checks
            _ => true
        };
    }
}

Note: The above code snippet uses a switch expression that is only available since C# 8. You can also use a regular switch statement .

The default value of a Guid is Guid.Empty , which passes validation of RequiredAttribute . You will probably have to create a custom attribute that checks the emptiness of a Guid. If you want to use an attribute.

Properties for value types are initialized with default values for the value type. If you change not nullable types to nullable (ie Guid to Guid? ), your validation should work as you expect:

public class PostCreate
{
    [Required(ErrorMessage = "content is required")]
    public string Content { get; set; }

    [Required(ErrorMessage = "blog id is required")]
    public Guid? BlogId { get; set; }
}

Content is validated as you expect because default value for string is null

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM