Swashbuckle.AspNetCore icon indicating copy to clipboard operation
Swashbuckle.AspNetCore copied to clipboard

GET array of objects parameters FromQuery are not properly serialized

Open trapgar opened this issue 4 years ago • 5 comments

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; }
}

image

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

trapgar avatar Sep 22 '20 16:09 trapgar

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.

domaindrivendev avatar Sep 22 '20 21:09 domaindrivendev

Ahh, too bad. Also based on the OpenAPI revision history, they probably won't be updating anytime soon. Thanks.

trapgar avatar Sep 22 '20 21:09 trapgar

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

domaindrivendev avatar Sep 22 '20 21:09 domaindrivendev

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.

harvzor avatar Aug 16 '21 09:08 harvzor

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; }

}

lucasgmagalhaes avatar Sep 22 '22 16:09 lucasgmagalhaes

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.

allamgr avatar Apr 20 '23 04:04 allamgr

Closing as external.

martincostello avatar May 04 '24 15:05 martincostello