RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.67k stars 1.23k forks source link

oneOf support in NSwag.CodeGeneration.CSharp.SwaggerToCSharpClientGenerator #1721

Open cpjolly opened 5 years ago

cpjolly commented 5 years ago

Hello @RSuter,

does NSwag.CodeGeneration.CSharp.SwaggerToCSharpClientGenerator currently support oneOf ? It seems to only convert the first item but ignores the second and following items.

Here is the part of the schema in question:

"framework-attribute-interface": {
            "type": "object",
            "description": "Interface for custom attribute value.",
            "properties": {
                "attribute_code": {
                    "type": "string",
                    "description": "Attribute code"
                },
                "value": {
                    oneOf: [
                        {
                            "type": "string",
                            "description": "Attribute value"
                        },
                        {
                            "type": "array",
                            "description": "Attribute values",
                            "items": {
                                "type": "string",
                                "description": "Attribute value"
                            }
                        }
                    ]
                }
            },
            "required": ["attribute_code", "value"]
        }

And here is the generated code:

    /// <summary>Interface for custom attribute value.</summary>
    [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.11.0.0 (Newtonsoft.Json v9.0.0.0)")]
    public partial class FrameworkAttributeInterface : System.ComponentModel.INotifyPropertyChanged
    {
        private string _attribute_code;
        private string _value;

        /// <summary>Attribute code</summary>
        [Newtonsoft.Json.JsonProperty("attribute_code", Required = Newtonsoft.Json.Required.Always)]
        [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
        public string Attribute_code
        {
            get { return _attribute_code; }
            set 
            {
                if (_attribute_code != value)
                {
                    _attribute_code = value; 
                    RaisePropertyChanged();
                }
            }
        }

        [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)]
        [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
        public string Value
        {
            get { return _value; }
            set 
            {
                if (_value != value)
                {
                    _value = value; 
                    RaisePropertyChanged();
                }
            }
        }

        public string ToJson() 
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(this);
        }

        public static FrameworkAttributeInterface FromJson(string data)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeObject<FrameworkAttributeInterface>(data);
        }

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) 
                handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }

    }
RicoSuter commented 5 years ago

No this is not supported. What would you expect as c# output for the property?

RicoSuter commented 5 years ago

Related: https://github.com/RSuter/NJsonSchema/issues/13

cpjolly commented 5 years ago

Hi @RSuter,

There are two possible approaches I can think of to support oneOf, anyOf & allOf in the generated c#.

  1. A separate field for each of the oneOf options, plus an enum flag field to indicate which is the active field or fields.
  2. A separate entity with the same option & enum fields, that is referenced from the parent entity.

In the mean time, the work-around I thought of is something like overriding the calling method in the generated code, pass a custom JsonConverter method to SerializeObject(), where the custom JsonConvertor converts the oneOf part of the json stream ?

Please let me know if I can help further.

Many thanks

Chris Jolly

RicoSuter commented 5 years ago

Yes, and also there is different output when oneOf is used for inheritance vs. your scenario here..

RicoSuter commented 5 years ago

Maybe the simplest solution in this case would be to just generate an object/JToken property...

cpjolly commented 5 years ago

Hi @RSuter,

Perhaps JToken is the right answer. Sorry, I don't know enough about the inner workings of your code or Newtonsoft to know if that's the right approach... I'd also be interested to know how easy it was to work with the resulting entities after deserialization.

RicoSuter commented 5 years ago

Hmm, I dont like exposing JToken or Newtonsoft.Json specific stuff (leaky abstraction) so maybe it's better to just expose object, but then the property is completely untyped - i.e. in your case not only string and string[] is allowed but everything...

Can you create a new issue in NJsonSchema for this? Because it has to be implemented there (DTO handling is in this library)

cpjolly commented 5 years ago

OK - I've created a new issue in NJsonSchema. Please let me know if you want me to copy over the example code from the above description

WarrenFerrell commented 4 years ago

@RicoSuter I believe this should be closed as a duplicate of https://github.com/RicoSuter/NSwag/issues/2313 ?

jeremyVignelles commented 3 years ago

I didn't read it through, but could it be merged with #2991 ?