diff --git a/src/NSwag.CodeGeneration/Models/OperationModelBase.cs b/src/NSwag.CodeGeneration/Models/OperationModelBase.cs index c4a19eacac..0b3827d6ba 100644 --- a/src/NSwag.CodeGeneration/Models/OperationModelBase.cs +++ b/src/NSwag.CodeGeneration/Models/OperationModelBase.cs @@ -213,7 +213,7 @@ public TParameterModel ContentParameter /// Gets a value indicating whether the operation consumes 'application/x-www-form-urlencoded'. public bool ConsumesFormUrlEncoded => _operation.ActualConsumes?.Any(c => c == "application/x-www-form-urlencoded") == true || - _operation.RequestBody?.Content.Any(mt => mt.Key == "application/x-www-form-urlencoded") == true; + _operation.RequestBody.ActualRequestBody?.Content.Any(mt => mt.Key == "application/x-www-form-urlencoded") == true; /// Gets the form parameters. public IEnumerable FormParameters => Parameters.Where(p => p.Kind == OpenApiParameterKind.FormData); diff --git a/src/NSwag.Core/OpenApiComponents.cs b/src/NSwag.Core/OpenApiComponents.cs index b1e416d111..f537bcc460 100644 --- a/src/NSwag.Core/OpenApiComponents.cs +++ b/src/NSwag.Core/OpenApiComponents.cs @@ -48,6 +48,16 @@ public OpenApiComponents(OpenApiDocument document) }; Responses = responses; + var requestBodies = new ObservableDictionary(); + requestBodies.CollectionChanged += (sender, args) => + { + foreach (var path in RequestBodies.Values) + { + path.Parent = document; + } + }; + RequestBodies = requestBodies; + var parameters = new ObservableDictionary(); parameters.CollectionChanged += (sender, args) => { @@ -90,6 +100,10 @@ public OpenApiComponents(OpenApiDocument document) [JsonProperty(PropertyName = "responses", DefaultValueHandling = DefaultValueHandling.Ignore)] public IDictionary Responses { get; } + /// Gets or sets the request bodies which can be used for all operations. + [JsonProperty(PropertyName = "requestBodies", DefaultValueHandling = DefaultValueHandling.Ignore)] + public IDictionary RequestBodies { get; } + /// Gets or sets the parameters which can be used for all operations. [JsonProperty(PropertyName = "parameters", DefaultValueHandling = DefaultValueHandling.Ignore)] public IDictionary Parameters { get; } diff --git a/src/NSwag.Core/OpenApiDocument.Serialization.cs b/src/NSwag.Core/OpenApiDocument.Serialization.cs index 58498b2184..2410acbda1 100644 --- a/src/NSwag.Core/OpenApiDocument.Serialization.cs +++ b/src/NSwag.Core/OpenApiDocument.Serialization.cs @@ -97,6 +97,7 @@ private static PropertyRenameAndIgnoreSerializerContractResolver CreateJsonSeria resolver.IgnoreProperty(typeof(OpenApiDocument), "definitions"); resolver.IgnoreProperty(typeof(OpenApiDocument), "parameters"); resolver.IgnoreProperty(typeof(OpenApiDocument), "responses"); + resolver.IgnoreProperty(typeof(OpenApiDocument), "requestBodies"); resolver.IgnoreProperty(typeof(OpenApiDocument), "securityDefinitions"); resolver.IgnoreProperty(typeof(OpenApiResponse), "schema"); @@ -210,5 +211,9 @@ private void UpdateServers(ICollection schemes, string host, stri /// Gets or sets the security definitions (Swagger only). [JsonProperty(PropertyName = "securityDefinitions", Order = 16, DefaultValueHandling = DefaultValueHandling.Ignore)] public IDictionary SecurityDefinitions => Components.SecuritySchemes; + + /// Gets or sets the request bodies which can be used for all operations (Swagger only). + [JsonProperty(PropertyName = "requestBodies", Order = 17, DefaultValueHandling = DefaultValueHandling.Ignore)] + public IDictionary RequestBodies => Components.RequestBodies; } } diff --git a/src/NSwag.Core/OpenApiMediaType.cs b/src/NSwag.Core/OpenApiMediaType.cs index bf16abfb08..2331bd0042 100644 --- a/src/NSwag.Core/OpenApiMediaType.cs +++ b/src/NSwag.Core/OpenApiMediaType.cs @@ -29,7 +29,7 @@ public JsonSchema Schema set { _schema = value; - Parent?.Parent?.UpdateBodyParameter(); + (Parent?.Parent as OpenApiOperation)?.UpdateBodyParameter(); } } @@ -41,7 +41,7 @@ public object Example set { _example = value; - Parent?.Parent?.UpdateBodyParameter(); + (Parent?.Parent as OpenApiOperation)?.UpdateBodyParameter(); } } diff --git a/src/NSwag.Core/OpenApiOperation.cs b/src/NSwag.Core/OpenApiOperation.cs index 98230d700d..bb02efa1c0 100644 --- a/src/NSwag.Core/OpenApiOperation.cs +++ b/src/NSwag.Core/OpenApiOperation.cs @@ -294,12 +294,12 @@ private OpenApiParameter CreateBodyParameter() private void UpdateBodyParameter(OpenApiParameter parameter) { parameter.Kind = OpenApiParameterKind.Body; - parameter.Name = RequestBody.ActualName; - parameter.Position = RequestBody.Position; - parameter.Description = RequestBody.Description; - parameter.IsRequired = RequestBody.IsRequired; - parameter.Example = RequestBody.Content.FirstOrDefault().Value?.Example; - parameter.Schema = RequestBody.Content.FirstOrDefault().Value?.Schema; + parameter.Name = RequestBody.ActualRequestBody.ActualName; + parameter.Position = RequestBody.ActualRequestBody.Position; + parameter.Description = RequestBody.ActualRequestBody.Description; + parameter.IsRequired = RequestBody.ActualRequestBody.IsRequired; + parameter.Example = RequestBody.ActualRequestBody.Content.FirstOrDefault().Value?.Example; + parameter.Schema = RequestBody.ActualRequestBody.Content.FirstOrDefault().Value?.Schema; } private void UpdateRequestBody(NotifyCollectionChangedEventArgs args) diff --git a/src/NSwag.Core/OpenApiParameter.cs b/src/NSwag.Core/OpenApiParameter.cs index 814bb87242..9f538e138a 100644 --- a/src/NSwag.Core/OpenApiParameter.cs +++ b/src/NSwag.Core/OpenApiParameter.cs @@ -225,7 +225,7 @@ public bool IsXmlBodyParameter var parent = Parent as OpenApiOperation; var consumes = parent?.ActualConsumes?.Any() == true ? parent.ActualConsumes : - parent?.RequestBody?.Content.Keys; + parent?.RequestBody?.ActualRequestBody.Content.Keys; return consumes?.Any() == true && consumes.Any(p => p.Contains("application/xml")) && @@ -256,7 +256,7 @@ public bool IsBinaryBodyParameter } else { - var consumes = parent?.RequestBody?.Content; + var consumes = parent?.RequestBody?.ActualRequestBody.Content; return (consumes?.Any(p => p.Key == "multipart/form-data") == true || consumes?.Any(p => p.Value.Schema?.IsBinary != false) == true) && consumes.Any(p => p.Key.Contains("*/*") && p.Value.Schema?.IsBinary != true) == false && @@ -286,7 +286,7 @@ public bool HasBinaryBodyWithMultipleMimeTypes } else { - var consumes = parent?.RequestBody?.Content; + var consumes = parent?.RequestBody?.ActualRequestBody.Content; return consumes?.Any() == true && (consumes.Count() > 1 || consumes.Any(p => p.Key.Contains("*"))); diff --git a/src/NSwag.Core/OpenApiRequestBody.cs b/src/NSwag.Core/OpenApiRequestBody.cs index 27cf0d34a3..bf8bf7b648 100644 --- a/src/NSwag.Core/OpenApiRequestBody.cs +++ b/src/NSwag.Core/OpenApiRequestBody.cs @@ -8,12 +8,13 @@ using System.Collections.Generic; using Newtonsoft.Json; +using NJsonSchema.References; using NSwag.Collections; namespace NSwag { /// The OpenApi request body (OpenAPI only). - public class OpenApiRequestBody + public class OpenApiRequestBody : JsonReferenceBase, IJsonReference { private string _name; private bool _isRequired; @@ -31,13 +32,17 @@ public OpenApiRequestBody() mediaType.Parent = this; } - Parent?.UpdateBodyParameter(); + (ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter(); }; Content = content; } [JsonIgnore] - internal OpenApiOperation Parent { get; set; } + internal object Parent { get; set; } + + /// Gets the actual request body, either this or the referenced request body. + [JsonIgnore] + public OpenApiRequestBody ActualRequestBody => Reference ?? this; /// Gets or sets the name. [JsonProperty(PropertyName = "x-name", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -47,7 +52,7 @@ public string Name set { _name = value; - Parent?.UpdateBodyParameter(); + (ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter(); } } @@ -59,7 +64,7 @@ public string Description set { _description = value; - Parent?.UpdateBodyParameter(); + (ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter(); } } @@ -75,7 +80,7 @@ public bool IsRequired set { _isRequired = value; - Parent?.UpdateBodyParameter(); + (ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter(); } } @@ -87,12 +92,35 @@ public int? Position set { _position = value; - Parent?.UpdateBodyParameter(); + (ActualRequestBody.Parent as OpenApiOperation)?.UpdateBodyParameter(); } } /// Gets the actual name of the request body parameter. [JsonIgnore] public string ActualName => string.IsNullOrEmpty(Name) ? "body" : Name; + + #region Implementation of IJsonReference + + [JsonIgnore] + IJsonReference IJsonReference.ActualObject => ActualRequestBody; + + [JsonIgnore] + object IJsonReference.PossibleRoot => (Parent as OpenApiOperation)?.Parent?.Parent; + + #endregion + + public override OpenApiRequestBody Reference + { + get + { + return base.Reference; + } + set + { + base.Reference = value; + (Parent as OpenApiOperation)?.UpdateBodyParameter(); + } + } } } \ No newline at end of file