diff --git a/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs b/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs index 08864f0282..9744df222b 100644 --- a/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs +++ b/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs @@ -408,14 +408,15 @@ private OpenApiParameter GenerateParameter( var isRequired = apiParameter.IsRequiredParameter(); - var schema = apiParameter.ModelMetadata != null - ? GenerateSchema( - apiParameter.Type, - schemaRepository, - apiParameter.PropertyInfo(), - apiParameter.ParameterInfo(), - apiParameter.RouteInfo) - : new OpenApiSchema { Type = "string" }; + var type = apiParameter.ModelMetadata?.ModelType ?? apiParameter.Type; + + var schema = type != null ? GenerateSchema( + type, + schemaRepository, + apiParameter.PropertyInfo(), + apiParameter.ParameterInfo(), + apiParameter.RouteInfo + ) : new OpenApiSchema() {Type = "string"}; var parameter = new OpenApiParameter { @@ -513,11 +514,13 @@ private OpenApiRequestBody GenerateRequestBodyFromBodyParameter( var isRequired = bodyParameter.IsRequiredParameter(); - var schema = GenerateSchema( - bodyParameter.Type, + var type = bodyParameter.ModelMetadata?.ModelType ?? bodyParameter.Type; + var schema = type != null ? GenerateSchema( + type, schemaRepository, bodyParameter.PropertyInfo(), - bodyParameter.ParameterInfo()); + bodyParameter.ParameterInfo() + ) : new OpenApiSchema() { Type = "string" }; return new OpenApiRequestBody { @@ -591,13 +594,13 @@ private OpenApiSchema GenerateSchemaFromFormParameters( ? formParameter.Name.ToCamelCase() : formParameter.Name; - var schema = formParameter.ModelMetadata != null - ? GenerateSchema( - formParameter.Type, - schemaRepository, - formParameter.PropertyInfo(), - formParameter.ParameterInfo()) - : new OpenApiSchema { Type = "string" }; + var type = formParameter.ModelMetadata?.ModelType ?? formParameter.Type; + var schema = type != null ? GenerateSchema( + type, + schemaRepository, + formParameter.PropertyInfo(), + formParameter.ParameterInfo() + ) : new OpenApiSchema() { Type = "string" }; properties.Add(name, schema); diff --git a/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeController.cs b/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeController.cs index e4cb622c4e..0ba04931a7 100644 --- a/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeController.cs +++ b/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeController.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; +using DotSwashbuckle.AspNetCore.TestSupport; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; @@ -19,6 +20,11 @@ public void ActionWithNoParameters() public void ActionWithParameter(string param) { } + public IntEnum ActionWithEnumParameter(IntEnum param) + { + return param; + } + public void ActionWithMultipleParameters(string param1, int param2) { } diff --git a/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs b/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs index 4636ace24c..832a35a598 100644 --- a/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs +++ b/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs @@ -370,6 +370,109 @@ public void GetSwagger_SetsOperationIdToNull_IfActionHasNoEndpointMetadata() Assert.Null(document.Paths["/resource"].Operations[OperationType.Post].OperationId); } + [Fact] + public void GetSwagger_SetsEnumRef_IfParameterIsEnum() + { + var methodInfo = typeof(FakeController).GetMethod(nameof(FakeController.ActionWithEnumParameter)); + var actionDescriptor = new ActionDescriptor + { + EndpointMetadata = null, + RouteValues = new Dictionary(StringComparer.Ordinal) + { + ["controller"] = methodInfo.DeclaringType.Name.Replace("Controller", string.Empty) + } + }; + var subject = Subject( + apiDescriptions: new[] + { + ApiDescriptionFactory.Create(actionDescriptor, methodInfo, groupName: "v1", httpMethod: "POST", + relativePath: "resource", + parameterDescriptions: new[] + { + new ApiParameterDescription + { + Name = "param", + Source = BindingSource.Query, + Type = typeof(string), // The type comes as string + ModelMetadata = ModelMetadataFactory.CreateForType(typeof(IntEnum)), + } + }, + supportedResponseTypes: new [] + { + new ApiResponseType + { + ApiResponseFormats = new [] { new ApiResponseFormat { MediaType = "application/json" } }, + StatusCode = 200, + }, + } + ) + } + ); + + var document = subject.GetSwagger("v1"); + + var operation = document.Paths["/resource"].Operations[OperationType.Post]; + + + Assert.Equal("IntEnum", operation.Responses["200"].Content.First().Value.Schema.Reference.Id); + Assert.Equal("IntEnum", operation.Parameters.First().Schema.Reference.Id); + Assert.Equal(ReferenceType.Schema, operation.Parameters.First().Schema.Reference.Type); + Assert.Equal(3, document.Components.Schemas["IntEnum"].Enum.Count); + } + + [Fact] + public void GetSwagger_SetsEnumRef_IfRequestBodyIsEnum() + { + var methodInfo = typeof(FakeController).GetMethod(nameof(FakeController.ActionWithEnumParameter)); + var actionDescriptor = new ActionDescriptor + { + EndpointMetadata = null, + RouteValues = new Dictionary(StringComparer.Ordinal) + { + ["controller"] = methodInfo.DeclaringType.Name.Replace("Controller", string.Empty) + } + }; + var subject = Subject( + apiDescriptions: new[] + { + ApiDescriptionFactory.Create(actionDescriptor, methodInfo, groupName: "v1", httpMethod: "POST", + relativePath: "resource", + parameterDescriptions: new[] + { + new ApiParameterDescription + { + Name = "param", + Source = BindingSource.Body, + Type = typeof(string), // The type comes as string + ModelMetadata = ModelMetadataFactory.CreateForType(typeof(IntEnum)), + } + }, + supportedRequestFormats: new[] + { + new ApiRequestFormat { MediaType = "application/json" } + }, + supportedResponseTypes: new [] + { + new ApiResponseType + { + ApiResponseFormats = new [] { new ApiResponseFormat { MediaType = "application/json" } }, + StatusCode = 200, + }, + } + ) + } + ); + + var document = subject.GetSwagger("v1"); + + var operation = document.Paths["/resource"].Operations[OperationType.Post]; + + + Assert.Equal("IntEnum", operation.Responses["200"].Content.First().Value.Schema.Reference.Id); + Assert.Equal("IntEnum", operation.RequestBody.Content.First().Value.Schema.Reference.Id); + Assert.Equal(3, document.Components.Schemas["IntEnum"].Enum.Count); + } + [Fact] public void GetSwagger_SetsDeprecated_IfActionHasObsoleteAttribute() { diff --git a/test/WebSites/Basic/Controllers/CrudActionsController.cs b/test/WebSites/Basic/Controllers/CrudActionsController.cs index 3e13b7ffdf..b5e38e2460 100644 --- a/test/WebSites/Basic/Controllers/CrudActionsController.cs +++ b/test/WebSites/Basic/Controllers/CrudActionsController.cs @@ -86,6 +86,17 @@ public void Patch(int id, [FromBody, Required]IDictionary update public void Delete(int id) { } + + [HttpGet("status", Name = "GetStatus")] + public void GetStatus(ProductStatus status) + { + } + + [HttpPost("status", Name = "GetStatus")] + public ProductStatus PostStatus([FromBody] ProductStatus status) + { + return status; + } } public enum ProductStatus