Swashbuckle.AspNetCore
Swashbuckle.AspNetCore copied to clipboard
GET array of objects parameters FromQuery are not properly serialized
Submitting a GET request to a controller action when the action has a parameter that is an array of complex objects does not send the request properly.
Example:
[Route("example")]
[ApiController]
public class ExampleController : Controller
{
[HttpGet]
public IActionResult Example([FromQuery]NameValuePair[] pairs)
{
return Ok();
}
}
public class NameValuePair
{
public string Name { get; set; }
public string Value { get; set; }
}
Neither submitting the above nor deleting the second value and setting the first to [{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]
work - both are url encoded.
Expected:
/example?pairs[0].Name=name1&pairs[0].Value=value1&pairs[1].Name=name2&pairs[1].Value=value2
Actual:
/example?pairs=%7B%22name%22%3A%22name1%22%2C%22value%22%2C%22value1%22%7D
Please let me know if I'm just not doing this correctly.
AspNetCore 3.1
Swashbuckle.AspNetCore 5.5.1
Swashbuckle.AspNetCore.Annotations 5.5.1
Swashbuckle is built on top of the Swagger / OpenAPI Specification and unfortunately the latest version of that specification DOES NOT currently support any way to describe the query-array-object serialization format you're using: See https://stackoverflow.com/questions/52892768/openapi-query-string-parameter-with-list-of-objects for more details.
Ahh, too bad. Also based on the OpenAPI revision history, they probably won't be updating anytime soon. Thanks.
I'm racking my brain to think of a workaround and unfortunately I'm not coming up with anything very feasible. All I can think of right now is perhaps wiring up a custom swagger-ui index (see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#customize-indexhtml) and from there injecting a custom request interceptor (see https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) that modifies the "Try it out" request, by re-formating the query string to the desired format. Pretty hacky and I don't have any good examples to provide either
This is still an issue.
https://github.com/OAI/OpenAPI-Specification/issues/1501 seems to relate to this specific issue, while most of the discussion is occurring on https://github.com/OAI/OpenAPI-Specification/issues/1706.
I've found a workaround:
public class SwaggerEnumerable<T> : IModelBinder where T : IEnumerable
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var val = bindingContext.ValueProvider.GetValue(bindingContext.FieldName);
var first = string.Concat("[", string.Join(",", val.ToList()), "]");
var model = JsonSerializer.Deserialize<T>(first);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
And in your model
public class Entity
{
[ModelBinder(typeof(SwaggerEnumerable<ComposedEntity[]>))]
public IEnumerable<ComposedEntity> Composeds { get; set; }
}
I'm racking my brain to think of a workaround and unfortunately I'm not coming up with anything very feasible. All I can think of right now is perhaps wiring up a custom swagger-ui index (see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#customize-indexhtml) and from there injecting a custom request interceptor (see https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) that modifies the "Try it out" request, by re-formating the query string to the desired format. Pretty hacky and I don't have any good examples to provide either
I was able to implement this and maybe will create a nuget package with extensions to implement it in your projects.
Closing as external.