3

I have a Controller action method which reads the Request.Body directly (instead of using File) for streaming and other purposes. The problem is there is no model binding and therefore Swagger doesn't document the contract. For example:

[HttpPost("upload")]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadAsync()
{
  // Read from Request.Body manually, expecting content type to be multipart/*
  return Ok();
}

When loading Swagger UI, there is no way to upload a file, etc.

Is there any way to support this with attributes in ASP.NET Core?

Cfun
  • 8,442
  • 4
  • 30
  • 62
Agendum
  • 1,697
  • 1
  • 18
  • 36

1 Answers1

0

The API:

 [HttpPost]  
    public async Task<IActionResult> Post(  
        [FromForm(Name = "myFile")]IFormFile myFile)  
    {  
            using (var fileContentStream = new MemoryStream())  
            {  
                await myFile.CopyToAsync(fileContentStream);  
                await System.IO.File.WriteAllBytesAsync(Path.Combine(folderPath, myFile.FileName), fileContentStream.ToArray());  
            }  
            return CreatedAtRoute(routeName: "myFile", routeValues: new { filename = myFile.FileName }, value: null); ;  
    }  

Operation filter

public class SwaggerFileOperationFilter : IOperationFilter  
{  
    public void Apply(Operation operation, OperationFilterContext context)  
    {  
        if (operation.OperationId == "Post")  
        {  
            operation.Parameters = new List<IParameter>  
            {  
                new NonBodyParameter  
                {  
                    Name = "myFile",  
                    Required = true,  
                    Type = "file",  
                    In = "formData"  
                }  
            };  
        }  
    }  
}  

Startup- ConfigureServices

services.AddSwaggerGen(  
    options =>  
    {  
        options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "My API", Version = "v1" });  

        options.OperationFilter<SwaggerFileOperationFilter>();  
    });  

The result in swagger UI: enter image description here

The source is:enter link description here

Brachy
  • 74
  • 6
  • I cannot use IFormFile because I need to support streaming the file as the file may be very large. Though IFormFile allows Swagger to behave as I want, it also buffers the file: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads – Agendum Dec 22 '20 at 21:50
  • have you tried: var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); as written this section:https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-5.0#upload-large-files-with-streaming? – Brachy Dec 23 '20 at 07:55
  • Yes that is exactly what I am doing, but even Microsoft's sample doesn't work with Swagger. There is no way to upload a document in Swagger. So the question is, how do I decorate the method such that Swagger will provide the ability to upload a document? – Agendum Dec 23 '20 at 20:26
  • I edited my answer, please share if you succeed with this... – Brachy Jan 04 '21 at 22:39
  • Your answer uses IFormFile which I cannot do in my case. Also I am using the newer OpenApi stuff which doesn't have things like NonBodyParameter. However your answer got me 90% of the way there. I was able to create my own market attribute and use my own OpenApi code to do the same thing. [This answer](https://stackoverflow.com/a/58516446) here does it... thanks for the pointer! – Agendum Jan 05 '21 at 04:54