Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate constructors for C# DTOs? #1020

Closed
ta-stott-oe opened this issue Oct 26, 2017 · 11 comments
Closed

Generate constructors for C# DTOs? #1020

ta-stott-oe opened this issue Oct 26, 2017 · 11 comments

Comments

@ta-stott-oe
Copy link

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; }
}
@zuckerthoben
Copy link

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.

@ta-stott-oe
Copy link
Author

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.

@RicoSuter
Copy link
Owner

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...

@zuckerthoben
Copy link

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.

@RicoSuter
Copy link
Owner

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...

@RicoSuter
Copy link
Owner

https://github.com/RSuter/NJsonSchema/wiki/Templates

@tastott
Copy link

tastott commented Oct 26, 2017

Excellent, thanks for the quick response @RSuter

@SaebAmini
Copy link

SaebAmini commented Sep 5, 2019

FYI this has been implemented here as a setting: RicoSuter/NJsonSchema#645

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

@mabead
Copy link

mabead commented Feb 3, 2020

@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?

@SaebAmini
Copy link

Yea and yes @mabead

@RicoSuter
Copy link
Owner

Please also consider/discuss here:
RicoSuter/NJsonSchema#1055

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants