The "required" modifier can help generate correct OpenAPI specs
A simple "required" modifier efficiently solves mandatory property issues in modern C# versions.
Table of contents
Context
Another thing that I recently found out about while working on a project mentioned in this other post is the required
modifier.
I needed to set up a simple model for Advertiser in my code with the following properties:
Property | Required |
Name | Yes |
Description | No |
No | |
Phone | No |
Contact Instructions | No |
First option
So that’s how I wrote the code for this model’s DTO class the first time:
public class AdvertiserDto : BaseDto
{
public string? Name { get; set; }
public string? Description { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string? ContactInstructions { get; set; }
}
It must either be constructorless or have a parameterless constructor because that is the class that is coming in and going out in the controller’s actions / APIs, so the serializer can create an instance and set the properties’ values.
As a modern C# project, it has nullable types enabled by default at the project level. That means, if I add a non-nullable string
property, it must be initialized after leaving the constructor, or the IDE will complain with a warning: Non-nullable property 'Name' is uninitialized. Consider declaring the property as nullable.
And for that reason, I could not make the string? Name
be just string Name
.
That will definitely work, but will be wrong in the OpenAPI specification that is generated in the API project, showing that the property is optional, but we know it’s not:
The required
modifier
Then, I was looking for a better solution for this, with some considerations:
I didn’t want to have this property marked as optional.
Can’t add parameters to the constructor and set it as non-nullable.
The
[Required]
attribute on a nullable property doesn’t make sense. It would leave the type in the screenshot above as something like:- “name: string | nullable [Required]“.
I also didn’t want to suppress any warnings.
So I changed it to a non-nullable string
property and checked what would be the options given by the IDE and/or ReSharper, and that one caught my attention:
I gave it a chance and the code ended up like this:
public class AdvertiserDto : BaseDto
{
public required string Name { get; set; }
public string? Description { get; set; }
// ...
That way, I ended up with the best possible solution:
Not using an optional type for nullable.
Not needing to add a constructor to initialize the property.
Serializer is able to serialize and deserialize the class without any issue.
OpenAPI specification gets correctly generated (screenshot below).
Though, every time I instantiate that class by myself, I need to set something to the Name property, like the example below, or it won’t compile.
var advertiser = new AdvertiserDto {
Name = "Bdvertiser"
};
But anyway, that’s not a problem at all, at least for now.
Conclusion
That’s how I found out about the required
modifier, which was introduced in C# at the end of 2022 with C# 11 (and .NET 7). Check the official docs here.
What I mean with “modern C# problems” in the title is that in older C# projects, specially when using .NET Framework, you don’t even have the optional string?
type, and the string
type is nullable by default. In those situations, something like the [Required]
attribute can help.