diff --git a/src/NSwag.Generation.AspNetCore.Tests/Responses/WrappedResponseTests.cs b/src/NSwag.Generation.AspNetCore.Tests/Responses/WrappedResponseTests.cs index b11a22144..f2196ee18 100644 --- a/src/NSwag.Generation.AspNetCore.Tests/Responses/WrappedResponseTests.cs +++ b/src/NSwag.Generation.AspNetCore.Tests/Responses/WrappedResponseTests.cs @@ -19,22 +19,26 @@ public async Task When_response_is_wrapped_in_certain_generic_result_types_then_ var settings = new AspNetCoreOpenApiDocumentGeneratorSettings(); // Act - var document = await GenerateDocumentAsync(settings, typeof(WrappedResponseController)); - + var document = await GenerateDocumentAsync(settings, typeof(WrappedResponseController)); + // Assert - OpenApiResponse GetOperationResponse(String ActionName) - => document.Operations.Where(op => op.Operation.OperationId == $"{nameof(WrappedResponseController).Substring(0, nameof(WrappedResponseController).Length - "Controller".Length )}_{ActionName}").Single().Operation.ActualResponses.Single().Value; - JsonObjectType GetOperationResponseSchemaType( String ActionName ) - => GetOperationResponse( ActionName ).Schema.Type; - var IntType = JsonSchema.FromType().Type; + OpenApiResponse GetOperationResponse(string actionName) => document.Operations + .Where(op => op.Operation.OperationId == $"{nameof(WrappedResponseController) + .Substring(0, nameof(WrappedResponseController).Length - "Controller".Length)}_{actionName}") + .Single().Operation.ActualResponses.Single().Value; + + JsonObjectType GetOperationResponseSchemaType(string actionName) => + GetOperationResponse(actionName).Schema.Type; + + var intType = JsonSchema.FromType().Type; Assert.Null(GetOperationResponse(nameof(WrappedResponseController.Task)).Schema); - Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.Int))); - Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfInt))); - Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfInt))); - Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ActionResultOfInt))); - Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfActionResultOfInt))); - Assert.Equal(IntType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfActionResultOfInt))); + Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.Int))); + Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfInt))); + Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfInt))); + Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ActionResultOfInt))); + Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.TaskOfActionResultOfInt))); + Assert.Equal(intType, GetOperationResponseSchemaType(nameof( WrappedResponseController.ValueTaskOfActionResultOfInt))); } } } \ No newline at end of file diff --git a/src/NSwag.Generation.WebApi.Tests/WrappedResponseTests.cs b/src/NSwag.Generation.WebApi.Tests/WrappedResponseTests.cs index 94097c8a0..5f0aa7fab 100644 --- a/src/NSwag.Generation.WebApi.Tests/WrappedResponseTests.cs +++ b/src/NSwag.Generation.WebApi.Tests/WrappedResponseTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web.Http; @@ -10,7 +9,6 @@ using NJsonSchema; - namespace NSwag.Generation.WebApi.Tests { [TestClass] @@ -18,67 +16,69 @@ public class WrappedResponseTests { public class WrappedResponseController : ApiController { - [HttpGet, Route( "task" )] + [HttpGet, Route("task")] public Task Task() { throw new NotImplementedException(); } - [HttpGet, Route( "int" )] + [HttpGet, Route("int")] public int Int() { throw new NotImplementedException(); } - [HttpGet, Route( "taskofint" )] + [HttpGet, Route("taskofint")] public Task TaskOfInt() { throw new NotImplementedException(); } - [HttpGet, Route( "valuetaskofint" )] + [HttpGet, Route("valuetaskofint")] public ValueTask ValueTaskOfInt() { throw new NotImplementedException(); } - [HttpGet, Route( "jsonresultofint" )] + [HttpGet, Route("jsonresultofint")] public JsonResult JsonResultOfInt() { throw new NotImplementedException(); } - [HttpGet, Route( "actionresultofint" )] + [HttpGet, Route("actionresultofint")] public CoreMvc.ActionResult ActionResultOfInt() { throw new NotImplementedException(); } - } [TestMethod] public async Task When_response_is_wrapped_in_certain_generic_result_types_then_discard_the_wrapper_type() { // Arrange - var generator = new WebApiOpenApiDocumentGenerator( new WebApiOpenApiDocumentGeneratorSettings() ); + var generator = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings()); // Act var document = await generator.GenerateForControllerAsync(); // Assert - OpenApiResponse GetOperationResponse( String ActionName ) - => document.Operations.Where( op => op.Operation.OperationId == $"{nameof(WrappedResponseController).Substring(0,nameof(WrappedResponseController).Length - "Controller".Length )}_{ActionName}" ).Single().Operation.ActualResponses.Single().Value; - JsonObjectType GetOperationResponseSchemaType( String ActionName ) - => GetOperationResponse( ActionName ).Schema.Type; - var IntType = JsonSchema.FromType().Type; + OpenApiResponse GetOperationResponse(string actionName) => document.Operations + .Where(op => op.Operation.OperationId == $"{nameof(WrappedResponseController) + .Substring(0, nameof(WrappedResponseController).Length - "Controller".Length)}_{actionName}") + .Single().Operation.ActualResponses.Single().Value; + + JsonObjectType GetOperationResponseSchemaType(string actionName) => + GetOperationResponse(actionName).Schema.Type; - Assert.IsNull( GetOperationResponse( nameof( WrappedResponseController.Task ) ).Schema ); - Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.Int ) ) ); - Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.TaskOfInt ) ) ); - Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.ValueTaskOfInt ) ) ); - Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.JsonResultOfInt ) ) ); - Assert.AreEqual( IntType, GetOperationResponseSchemaType( nameof( WrappedResponseController.ActionResultOfInt ) ) ); + var intType = JsonSchema.FromType().Type; + Assert.IsNull(GetOperationResponse(nameof(WrappedResponseController.Task)).Schema); + Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.Int))); + Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.TaskOfInt))); + Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.ValueTaskOfInt))); + Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.JsonResultOfInt))); + Assert.AreEqual(intType, GetOperationResponseSchemaType(nameof(WrappedResponseController.ActionResultOfInt))); } } } \ No newline at end of file diff --git a/src/NSwag.Generation/GenericResultWrapperTypes.cs b/src/NSwag.Generation/GenericResultWrapperTypes.cs index a8791f0f1..8207e3d11 100644 --- a/src/NSwag.Generation/GenericResultWrapperTypes.cs +++ b/src/NSwag.Generation/GenericResultWrapperTypes.cs @@ -1,25 +1,23 @@ using System; -using System.Linq; - namespace NSwag.Generation { internal static class GenericResultWrapperTypes { - internal static bool IsGenericWrapperType( string typeName ) - => - typeName == "Task`1" || - typeName == "ValueTask`1" || - typeName == "JsonResult`1" || - typeName == "ActionResult`1" - ; + internal static bool IsGenericWrapperType(string typeName) => + typeName == "Task`1" || + typeName == "ValueTask`1" || + typeName == "JsonResult`1" || + typeName == "ActionResult`1"; - internal static void RemoveGenericWrapperTypes(ref T o, Func getName, Func unwrap) + internal static T RemoveGenericWrapperTypes(T type, Func getName, Func unwrap) { // We iterate because a common signature is public async Task> Action() - while (IsGenericWrapperType(getName(o))) + while (IsGenericWrapperType(getName(type))) { - o = unwrap(o); + type = unwrap(type); } + + return type; } } } diff --git a/src/NSwag.Generation/OpenApiSchemaGenerator.cs b/src/NSwag.Generation/OpenApiSchemaGenerator.cs index c6bb2a980..a5f20b941 100644 --- a/src/NSwag.Generation/OpenApiSchemaGenerator.cs +++ b/src/NSwag.Generation/OpenApiSchemaGenerator.cs @@ -51,18 +51,19 @@ protected override void GenerateObject(JsonSchema schema, JsonTypeDescription ty } } - /// Generetes a schema directly or referenced for the requested schema type; also adds nullability if required. - /// The resulted schema type which may reference the actual schema. - /// The type of the schema to generate. - /// Specifies whether the property, parameter or requested schema type is nullable. - /// The schema resolver. - /// An action to transform the resulting schema (e.g. property or parameter) before the type of reference is determined (with $ref or allOf/oneOf). - /// The requested schema object. - public override TSchemaType GenerateWithReferenceAndNullability( + /// Generetes a schema directly or referenced for the requested schema type; also adds nullability if required. + /// The resulted schema type which may reference the actual schema. + /// The type of the schema to generate. + /// Specifies whether the property, parameter or requested schema type is nullable. + /// The schema resolver. + /// An action to transform the resulting schema (e.g. property or parameter) before the type of reference is determined (with $ref or allOf/oneOf). + /// The requested schema object. + public override TSchemaType GenerateWithReferenceAndNullability( ContextualType contextualType, bool isNullable, JsonSchemaResolver schemaResolver, Action transformation = null) { - GenericResultWrapperTypes.RemoveGenericWrapperTypes (ref contextualType,t=>t.TypeName,t=>t.OriginalGenericArguments[0]); + contextualType = GenericResultWrapperTypes.RemoveGenericWrapperTypes( + contextualType, t => t.TypeName, t => t.OriginalGenericArguments[0]); if (IsFileResponse(contextualType)) { diff --git a/src/NSwag.Generation/Processors/OperationResponseProcessorBase.cs b/src/NSwag.Generation/Processors/OperationResponseProcessorBase.cs index 0b57477d0..eedab013f 100644 --- a/src/NSwag.Generation/Processors/OperationResponseProcessorBase.cs +++ b/src/NSwag.Generation/Processors/OperationResponseProcessorBase.cs @@ -94,7 +94,7 @@ protected void UpdateResponseDescription(OperationProcessorContext operationProc protected XElement GetResponseXmlDocsElement(MethodInfo methodInfo, string responseCode) { var operationXmlDocsNodes = GetResponseXmlDocsNodes(methodInfo); - try + try { return operationXmlDocsNodes?.SingleOrDefault(n => n.Name == "response" && n.Attributes().Any(a => a.Name == "code" && a.Value == responseCode)); } @@ -268,7 +268,8 @@ private void LoadDefaultSuccessResponse(ParameterInfo returnParameter, string su returnType = typeof(void); } - GenericResultWrapperTypes.RemoveGenericWrapperTypes (ref returnType,t=>t.Name,t=>t.GenericTypeArguments[0]); + returnType = GenericResultWrapperTypes.RemoveGenericWrapperTypes( + returnType, t => t.Name, t => t.GenericTypeArguments[0]); if (IsVoidResponse(returnType)) {