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 (e.g. 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.