I'm using a C# 9.0 record
type as a binding model for a .NET 5.0 Web API project. Some of the properties are required.
I'm using the record
positional syntax, but am receiving errors.
public record Mail(
System.Guid? Id,
[property: Required]
string From,
[property: Required]
string[] Tos,
[property: Required]
string Subject,
string[]? Ccs,
string[]? Bccs,
[property: Required]
Content[] Contents,
Attachment[]? Attachments
);
This is then exposed as the binding model for my Index
action:
public async Task<ActionResult> Index(Service.Models.Mail mailRequest)
{
…
}
Whenever I try to make a request, however, I receive the following error:
Record type 'Service.Models.Mail' has validation metadata defined on property 'Contents' that will be ignored. 'Contents' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
I tried removing the attribute on the Contents
property, but it then fails for the next (prior) property. I tried using [param: …]
instead of [property: …]
, as well as mixing them, but keep getting the same kind of error.
I looked around the web, and haven't found any suggestion of handling annotations differently for C# 9 records. I did my best, but I'm out of ideas—outside of converting my records to POCOs.
[param: …]
attribute target to cover it. Out of curiosity, have you tried assigning these as explicit properties on your record, instead of as implicit properties using the positional constructor syntax? I'm not sure if it would make a difference, but given that the error highlights the issue with the constructor, it may be useful to see how that impacts the error. I also assume that you tried this without any attribute target (i.e., removingproperty:
entirely)? – ElectioneerRequired
on a property isn't meaningful as there's no way to change a property's value once set. If you want a property to be non-null, you'll have to perform validation on the constructor parameter itself – Reedbuck[StringLength]
attribute so implicitly[Required]
for parameters is just an edge caseRecord type 'AuthCodeRequest' has validation metadata defined on property 'AuthCode' that will be ignored. 'AuthCode' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
But in my case replacing property with param is working. I don't need swagger though but validation works properly now – SpaciousRequired
just doesn't work, but other attributes such asRange
work. Using[property: Range(1,2)]
or[property: Required]
will fail with the error in the comment above. Using[field: Range(1,2)]
or[field: Required]
has no impact (as expected). Using[Range(1,2)]
or[param: Range(1,2)]
works as expected (i.e. the attribute is implicitly required and the range is validated), But using[Required]
or[param: Required]
has no impact. – Birdlime<Nullable>enable</Nullable>
in the .csproj, there is a difference of validation for regular classes i.e. properties withget; set;
: if declaring the property asstring?
you get a non-required field, and if declared asstring
you get a required field. But this doesn't work with records constructed with positional parameters. – Birdlime