Question: I'm trying to upload a file with some metadata:

```
Upload(IFormFile file, [FromForm]IEnumerable<MetadataValue> list)

public class MetadataValue
{
    public Metadata Metadata { get; set; }
    public string Value { get; set; }
}

public enum Metadata
{
    Cat1,
    Cat2
}

```

A list of `MetadataValue` is displayed like an array of string inputs. I was not able to determine how should I pass the data to the controller - I'm always receiving an empty collection.

[![enter image description here](https://i.stack.imgur.com/McJ1j.png)](https://i.stack.imgur.com/McJ1j.png)

Everything is working when I'm sending a request from Postman. This is handled by dot pattern/notation.

[![enter image description here](https://i.stack.imgur.com/SVvFJ.png)](https://i.stack.imgur.com/SVvFJ.png)

In Postman each parameter and each property of a complex object is being sent as a separate field:

```
curl --location --request POST 'https://localhost:44395/api/document/upload' \
--form 'file=@/C:/FilterDraft.txt' \
--form 'list[0].metadata=Cat1' \
--form 'list[0].value=ABC' \
--form 'list[1].metadata=Cat2' \
--form 'list[1].value=DEF'

```

How can I achieve this in Swagger UI?  

How can I configure Swagger for better UI generation?

I'm using:

* .NET Core 3.1
* Swashbuckle.AspNetCore 5.5.1

Answer: 
---

Solution:
---------

To add examples you have to decorate the action method with SwaggerOperationFilter:

```
[SwaggerOperationFilter(typeof(OperationFilter))]
Upload(IFormFile file, [FromForm]IEnumerable<MetadataValue> list)
[...]
internal class UploadOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.OperationId != nameof(DocumentController.Upload))
        {
            return;
        }
        if (operation.RequestBody.Content.TryGetValue("multipart/form-data", out var openApiMediaType))
        {
            var options = new JsonSerializerOptions { WriteIndented = true };
            options.Converters.Add(new JsonStringEnumConverter());

            var array = new OpenApiArray
            {
                new OpenApiString(JsonSerializer.Serialize(new MetadataValue {Metadata = Metadata.Cat1, Value = "ABC"}, options)),
                new OpenApiString(JsonSerializer.Serialize(new MetadataValue {Metadata = Metadata.Cat2, Value = "DEF"}, options))
            };

            openApiMediaType.Schema.Properties["metadata"].Example = array;
        }
    }
}

```

To get values in the controller (not empty collection), you have to add custom ModelBinder:

```
[ModelBinder(BinderType = typeof(MetadataValueModelBinder))]
public class MetadataValue
{
    public Metadata Metadata { get; set; }
    public string Value { get; set; }
}

public class MetadataValueModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));

            var values = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            if (values.Length == 0)
                return Task.CompletedTask;

            var options = new JsonSerializerOptions();
            options.Converters.Add(new JsonStringEnumConverter());

            var deserialized = JsonSerializer.Deserialize(values.FirstValue, bindingContext.ModelType, options);

            bindingContext.Result = ModelBindingResult.Success(deserialized);
            return Task.CompletedTask;
        }
    }

```
Following the answer provided by ***rperwinski***, if you are using ***Newtonsoft.Json*** instead of ***System.Text.Json***, you should replace:

Inside the *IOperationFilter*

```
var options = new JsonSerializerSettings();
options.Converters.Add(new StringEnumConverter());
options.Formatting == Formatting.Indented;

var array = new OpenApiArray
    {
        new OpenApiString(JsonConvert.SerializeObject(new MetadataValue {Metadata = Metadata.Cat1, Value = "ABC"}, options)),
        new OpenApiString(JsonConvert.SerializeObject(new MetadataValue {Metadata = Metadata.Cat2, Value = "DEF"}, options))
    };

```

And inside the *IModelBinder*

```
var options = new JsonSerializerSettings();
options.Converters.Add(new StringEnumConverter());

var deserialized = JsonConvert.DeserializeObject(values.FirstValue, bindingContext.ModelType, options);

```