Swashbuckle.AspNetCore icon indicating copy to clipboard operation
Swashbuckle.AspNetCore copied to clipboard

Unable to make a field required when using a record DTO

Open jeffw-wherethebitsroam opened this issue 2 years ago • 11 comments

If I have a simple POST controller like:

    [HttpPost()]
    public ActionResult<TestDto> Create([FromBody, BindRequired] TestDto testDto)
    {
        return testDto;
    }

where TestDto is defined as:

public record TestDto([property: Required] int Id);

I get the correct OpenAPI spec generated:

      "TestDto": {
        "required": [
          "id"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },

But it fails at runtime:

System.InvalidOperationException: Record type 'TestDto' has validation metadata defined on property 'Id' that will be ignored. 'Id' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.

If I follow the advice in the exception and add the Required attribute to the param, I get:

public record TestDto([param: Required] int Id);

And the API is now happy, but the generated OpenAPI spec no longer has id as required:

      "TestDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },

Is there any way to use a record DTO with required fields that works with both the API and generates the correct spec?

jeffw-wherethebitsroam avatar Jun 22 '22 09:06 jeffw-wherethebitsroam

Having the same issue, please post if you find a solution

jonasbjoralt avatar Oct 13 '22 11:10 jonasbjoralt

I'm having the same issue, even when use [FromForm]

[HttpPost()]
public ActionResult<TestDto> Create([FromForm, BindRequired] TestDto testDto) 
{ 
    return testDto;
}

An alternative could be something like this, that at least work for me:

public record TestDto
{
   [Required] 
   public  int Id {get; int;}
}

or

public record TestDto
{
   [Required] 
   public int Id {get; get;}
}

But Any Solution using initial constructor?

Thanks

juanluelguerre avatar Nov 30 '22 21:11 juanluelguerre

I also have the same problem.

For me the following solution works but it's still not ideal because my IDE suggests converting it to a primary constructor

public record TestDto
{
    public TestDto(int id)
    {
        Id = id;
    }
    
    [Required] public int Id { get; init; }
};

nickbannink avatar Feb 14 '23 15:02 nickbannink

Having the same issue, would be nice to see a workaround/fix so that we could use the primary constructor feature.

toni-schmitt avatar Sep 18 '23 07:09 toni-schmitt

This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made.

github-actions[bot] avatar Apr 21 '24 01:04 github-actions[bot]

Same problem!

Neftedollar avatar Apr 24 '24 06:04 Neftedollar

Same here!

JenPullUp avatar Apr 27 '24 05:04 JenPullUp