Nswag: API Explorer: Improve nested IFormFile

Created on 26 Sep 2018  路  4Comments  路  Source: RicoSuter/NSwag

Not working:

public class FileUploadModel
{
    public IFormFile File { get; set; }
}

[ApiExplorerSettings(IgnoreApi = false, GroupName = nameof(HelloController))]
[ApiController]
[Route("Hello")]
public class HelloController : Controller
{
    [HttpPut("Upload")]
    [RequestSizeLimit(100_000_000)]
    // 100MiB
    public string PostFile(FileUploadModel upload)
    {
        return upload.File.FileName;
    }
}

Output:

    "parameters": [
      {
        "name": "upload",
        "in": "body",
        "required": true,
        "schema": {
          "$ref": "#/definitions/FileUploadModel"
        },
        "x-nullable": false
      }
    ],

Working as expected:

[ApiExplorerSettings(IgnoreApi = false, GroupName = nameof(HelloController))]
[ApiController]
[Route("Hello")]
public class HelloController : Controller
{
    [HttpPut("Upload")]
    [RequestSizeLimit(100_000_000)]
    // 100MiB
    public string PostFile(IFormFile upload)
    {
        return upload.FileName;
    }
}

Output:

    "parameters": [
      {
        "type": "file",
        "name": "upload",
        "in": "formData",
        "required": true,
        "x-nullable": false
      }
    ],

I'd expect api explorer to handle a complex parameter as a collection of params and not a single complex param if a property is of type IFormFile...

Repro: https://github.com/jeremyVignelles/TestNSwagNetCoreApp/tree/repro/iFormFile

/cc @jeremyVignelles

NSwag.AspNetCore enhancement

Most helpful comment

Hi,

So finally there were no issue from .Net Core. It's more things we need to know when we send Data and Files to a .net Core API.

From client side, we need to:

  • send data as FormData (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/client/src/app/services/api.services.extensions.ts#L52)
  • even if there is many files, we need to set the same name (no bracket needed)
    it s the opposite with Array of object which need brackets.
    here is an example:

name: Parent1
files: (binary)
files: (binary)
children[0].name: Child1
children[0].files: (binary)
children[0].files: (binary)
children[1].name: Child2
children[1].files: (binary)
children[1].files: (binary)
children[1].files: (binary)

from server side, what we need to know:

  • Action must use the [FromForm] attribute (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/server/TestMultipleUpload.Api/Controllers/FamilyController.cs#L24)
  • Dto must use IFormFile or IFormFile[] (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/server/TestMultipleUpload.Api/Controllers/Dtos/ParentDto.cs#L11)

My suggestion for NSwag,

  • when your server side has a property typed as IFormFile or IFormFile[] then convert it client side to File and File[].
  • This is what nswag currently generates which doesnt work:
    if (dto !== null && dto !== undefined)
    content_.append("dto", dto.toString());
    To convert my object to FormData, I used this function (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/client/src/app/services/api.services.extensions.ts#L57). You ll probably do something more efficient :)

@RSuter let me know if it helps you to improve NSwag or if you have any questions :)

All 4 comments

@pranavkm what do you think?

Hi,

I did a repository too where you can see the problem:
https://github.com/ranouf/TestMultipleUpload

I think there it could exist bug on both side (server & client).
For server, I created an issue here: https://github.com/dotnet/core/issues/1967.
For client, here: https://github.com/RSuter/NSwag/issues/1633

Currently the client generated by nswag generates wrong service, I m not able to get the string values or IFormFile values server side (even in the HttpContext). So I overwrited the method and now, all the values are sent to the server. I can see the string values correctly binder to the DTO but not the IFormFile (but they are in the HttpContext).

Let me know for any updates, I m interested to get a working solution :)

It s confirmed, there is a bug with IFormFile binding on .net core 2.1 (https://github.com/aspnet/Mvc/issues/8527#issuecomment-425978956).

A fix has been proposed and it s available on the nightly builds.

I uploaded my repository (https://github.com/ranouf/TestMultipleUpload) to get the last version of .net Core, but I continue to have some issues, maybe the request is not correctly configured.

I will let you know when I will have more details.

Hi,

So finally there were no issue from .Net Core. It's more things we need to know when we send Data and Files to a .net Core API.

From client side, we need to:

  • send data as FormData (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/client/src/app/services/api.services.extensions.ts#L52)
  • even if there is many files, we need to set the same name (no bracket needed)
    it s the opposite with Array of object which need brackets.
    here is an example:

name: Parent1
files: (binary)
files: (binary)
children[0].name: Child1
children[0].files: (binary)
children[0].files: (binary)
children[1].name: Child2
children[1].files: (binary)
children[1].files: (binary)
children[1].files: (binary)

from server side, what we need to know:

  • Action must use the [FromForm] attribute (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/server/TestMultipleUpload.Api/Controllers/FamilyController.cs#L24)
  • Dto must use IFormFile or IFormFile[] (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/server/TestMultipleUpload.Api/Controllers/Dtos/ParentDto.cs#L11)

My suggestion for NSwag,

  • when your server side has a property typed as IFormFile or IFormFile[] then convert it client side to File and File[].
  • This is what nswag currently generates which doesnt work:
    if (dto !== null && dto !== undefined)
    content_.append("dto", dto.toString());
    To convert my object to FormData, I used this function (https://github.com/ranouf/TestMultipleUpload/blob/eab8ff287fff3bd464d9c02860dce83474c5a75c/client/src/app/services/api.services.extensions.ts#L57). You ll probably do something more efficient :)

@RSuter let me know if it helps you to improve NSwag or if you have any questions :)

Was this page helpful?
0 / 5 - 0 ratings