Search code examples
c#asp.net-coreswaggerswagger-uiwebapi

Swagger UI, array of objects in multipart/form-data


enter image description here

I have a PUT query in multipart/form-data format.

I need to send an array of objects of class. The class looks like:

    public class TestObjects
    {
       public long Id { get; set; }

       public string Name { get; set; }

       public decimal MaxScore { get; set; }
    }

What should I write in this swagger field?


Solution

  • It is a known issue on github and it seems still not be fixed(I have also tried .NET 6).

    You need put data like below: enter image description here

    Then custom model binder like below:

    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() { PropertyNameCaseInsensitive = true };
    
            var deserialized = JsonSerializer.Deserialize(values.FirstValue, bindingContext.ModelType, options);
    
            bindingContext.Result = ModelBindingResult.Success(deserialized);
            return Task.CompletedTask;
        }
    }
    

    Add the model binder to the model class:

    [ModelBinder(BinderType = typeof(MetadataValueModelBinder))]
    public class TestObjects
    {
        public long Id { get; set; }
    
        public string Name { get; set; }
    
        public decimal MaxScore { get; set; }
    }
    

    You can see the schema example does not display the example, if you want to display the example you need also custom IOperationFilter:

    public class CustomOperationFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            
            if (operation.RequestBody!=null && operation.RequestBody.Content.TryGetValue("multipart/form-data", out var openApiMediaType))
            {
                var options = new JsonSerializerOptions { WriteIndented = true };
                var array = new OpenApiArray
                 {
                new OpenApiString(JsonSerializer.Serialize(new TestObjects {Id = 0, Name="string",MaxScore=0}, options)),
                 };
    
                openApiMediaType.Schema.Properties["Competences"].Example = array;
            }
        }
    }
    

    Register the IOperationFilter:

    services.AddSwaggerGen(c =>
    {
        c.OperationFilter<CustomOperationFilter>();
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApi5_0", Version = "v1" });
    });
    

    Another workaround is you can use [FromBody] instead of using [FromForm]:

    [HttpPut]
    public void Post([FromBody] List<TestObjects> Competences)
    {
    
    }
    

    Put json data like below:

    [
      {
        "id": 1,
        "name": "aa",
        "maxScore": 1
      },
      {
        "id": 2,
        "name": "bb",
        "maxScore": 2
      }
    ]
    

    Result:

    enter image description here