4

Environment

  • C# 7.2
  • .NET core 2.0/2.1
  • Kestrel

I am trying to get a file upload working thru web api. It seemed simple enough but I must be missing something trivial.

I've been searching the web, but I haven't found a full, working example to download.

I've tried plugging in the snippets showing how to do this but have not been able to get a fully working solution.

I've created my own, simple test project. Here are the key pieces.

Startup.cs

public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services .AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseStaticFiles(); app.UseDeveloperExceptionPage(); } app.UseMvc(); } } 

ValuesController

[Produces("application/json")] [Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { public ValuesController() { } [HttpPost("upload")] public async Task<IActionResult> Upload(IFormFile file) { try { using (Stream strm = file?.OpenReadStream()) { return Ok($"File uploaded had {file?.Length ?? -1} bytes"); } } catch (Exception ex) { return BadRequest(ex); } } } 

If I call this web method from postman (must support this) using:

http://localhost:5000/api/values/upload

Header: Content-Type: multipart/form-data;boundary="boundary"

Body: Form-Data with 1 param named 'file' and sent as a file, not text.

Kestrel responds with:

System.IO.IOException: Unexpected end of Stream, the content may have already been read by another component.

I also tried with a simple html form:

<form method="post" enctype="multipart/form-data" action="http://localhost:5000/api/values/upload"> <div> <p>Upload one or more files using this form:</p> <input type="file" name="files" /> </div> <div> <input type="submit" value="Upload" /> </div> </form> 

This approach actually makes it into the web method, but the IFormFile parameter is always null.

It seems like postman is finding the web method, sending the data and that the stream is being read multiple times. I found several refs to an DisableFormValueModelBinding attribute, but it didn't seem to help. It seems odd that I would need a custom attribute in order to use the IFormFile that MS provides.

On the form side of things, I'm not why the file isn't being sent.

If anyone can point me to working example to download, or see what I am overlooking, it would be appreciated.

0

2 Answers 2

5

Your question talks of two problems, where the second simply relates to the first, which itself is your real concern here.

  1. System.IO.IOException: Unexpected end of Stream, the content may have already been read by another component.

    This occurs because you're explicitly setting the Content-Type header when using Postman (confirmed in the comments). This means that the request being sent to your ASP.NET Core endpoint is incomplete, causing the error shown above. Instead, just remove this header and let Postman take care of it for you.

  2. This approach actually makes it into the web method, but the IFormFile parameter is always null.

    The IFormFile instance here is null simply because the name used in the HTML form (files) and the name of the IFormFile parameter (file) do not match. All you need to do here is use e.g. file in both locations.

Sign up to request clarification or add additional context in comments.

Comments

0
[HttpPost("UploadFiles")] public async Task<IActionResult> Post(List<IFormFile> files) { long size = files.Sum(f => f.Length); // full path to file in temp location var filePath = Path.GetTempFileName(); foreach (var formFile in files) { if (formFile.Length > 0) { using (var stream = new FileStream(filePath, FileMode.Create)) { await formFile.CopyToAsync(stream); } } } 

Try this

https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1

 // process uploaded files // Don't rely on or trust the FileName property without validation. return Ok(new { count = files.Count, size, filePath}); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.