Nswag: Generate constructors for C# DTOs?

Created on 26 Oct 2017  路  11Comments  路  Source: RicoSuter/NSwag

When generating a DTO type for a C# client with NSwag, is it possible to generate a constructor which has parameters for each of the DTO's properties?

Ideally:

  • [Required] properties would be mandatory constructor parameters and others would be optional with default values.
  • the parameterless constructor required by Json.Net (marked [JsonConstructor]) would be private / protected (or there would be an option for this).

For example, given this DTO definition:
"User": { "type": "object", "additionalProperties": false, "properties": { "Id": { "type": "string" }, "Name": { "type": "string" } }, "required": [ "Id" ] }

...NSwag would generate something like this DTO type (in "Poco" mode):

````
public class User
{
[JsonConstructor]
protected User() {}

public User(string id, string name = null)
{
    this.Id = id;
    this.Name = name;
}

public string Id { get; set; } // Ideally these would be private set, or even readonly fields, but I won't push my luck!
public string Name { get; set; }

}
````

done discussion

Most helpful comment

Hi @zuckerthoben, the purpose of the constructor is to ensure at compile-time that the required properties have a value. (Or at least make it harder not to supply a value).

For example, let's say I'm going to POST a User (as described above) to my API using the NSwag-generated client. This constructor (and the inaccessibility of the parameterless constructor) tells me as a consumer of the API that I need to supply a value for Id. Otherwise, I could just write new User { Name = "Foo" }, send it off and receive a Bad Request from the API.

To continue the example, perhaps the API and client have now been updated and User has a new mandatory property, say DateOfBirth. It is desirable for this to cause a compiler error in my code and force me to start providing a value for that too.

I guess this pattern is more useful for data being sent to the API but I'd argue it also has value for response DTOs because it helps when creating expected objects for tests.

As for having many parameters, yes I would gladly use a constructor with 10+ parameters rather than having to figure out which of 10+ properties I need to set. Also, arguably a class with 10+ properties is too big and should probably be split up, but that is a different discussion.

I am currently implementing the constructors myself but it is quite laborious and likely to lead to omissions as the DTOs change.

All 11 comments

What exactly are you gaining from this? And do you really want a constructor with x parameters, with x possibly being 10 or more?
If you really need parameter constructors I would implement them myself.

Hi @zuckerthoben, the purpose of the constructor is to ensure at compile-time that the required properties have a value. (Or at least make it harder not to supply a value).

For example, let's say I'm going to POST a User (as described above) to my API using the NSwag-generated client. This constructor (and the inaccessibility of the parameterless constructor) tells me as a consumer of the API that I need to supply a value for Id. Otherwise, I could just write new User { Name = "Foo" }, send it off and receive a Bad Request from the API.

To continue the example, perhaps the API and client have now been updated and User has a new mandatory property, say DateOfBirth. It is desirable for this to cause a compiler error in my code and force me to start providing a value for that too.

I guess this pattern is more useful for data being sent to the API but I'd argue it also has value for response DTOs because it helps when creating expected objects for tests.

As for having many parameters, yes I would gladly use a constructor with 10+ parameters rather than having to figure out which of 10+ properties I need to set. Also, arguably a class with 10+ properties is too big and should probably be split up, but that is a different discussion.

I am currently implementing the constructors myself but it is quite laborious and likely to lead to omissions as the DTOs change.

I have the same opinian as @zuckerthoben here... but with the new Liquid template engine (already available as opt-in feature), you can replace specific templates and enhance them. I'll add an extension template to the head of the DTO class so that you can inject a custom generated ctor...

I agree that compile-time required properties improve the inner-development cycle and softens the learning curve when implementing an api.
An optional solution that I could imagine would be to create a constructor for a dto that contains the required properties as parameters.

With NSwag v11.11.2 you can now enable Liquid templates (UseLiquidTemplates) and then you can override the Class.Constructor template with your custom constructor...

Excellent, thanks for the quick response @RSuter

FYI this has been implemented here as a setting: https://github.com/RicoSuter/NJsonSchema/pull/645

You just need to set classStyle to Record. One caveat is it doesn't filter non-required properties.

@SaebAmini When you say that it doesn't filter non-required propertie, do you mean that it will generate a constructor with the signature public User(string id, string name) instead of public User(string id, string name = null)? So, by looking at the constructor there is no way to differentiate optional from required properties?

Yea and yes @mabead

Please also consider/discuss here:
https://github.com/RicoSuter/NJsonSchema/pull/1055

Was this page helpful?
0 / 5 - 0 ratings