How to Upload Files in ASP.NET Core

How to upload file to an ASP.NET Core controller?

Instead of

UploadFile([FromBody] IFormFile file)

Use

UploadFile([FromForm] IFormFile file)

And

fileUploaded(files) {
files.forEach(async ifile => {
const formData = new FormData();
formData.append('file', ifile)
await axios.post('http://localhost:5000/api/upload', formData)
.then(res => {
console.log(res)
}).catch(err => {
console.error(err);
});
});
}

How do I do file upload using ASP.NET Core 6 minimal api?

Currently out of the box support for binding in Minimal APIs is quite limited. Supported binding sources:

  • Route values
  • Query string
  • Header
  • Body (as JSON)
  • Services provided by dependency injection
  • Custom

NOTE: Binding from forms is not natively supported in .NET 6

You can either leverage custom binding or use special types handling:

app.MapPost("/upload", (HttpRequest request) =>
{
//Do something with the file
var files = request.Form.Files;
return Results.Ok();
})
.Accepts("multipart/form-data")
.Produces(200);

ASP.NET Core web application - How to upload large files

I've implemented a similar large file controller but using mongoDB GridFS.

In any case, streaming is the way to go for large files because it is fast and lightweight.
And yes, the best option is to save the files on your server storage before you send.
One suggestion is, add some validations to allow specefic extensions and restrict execution permissions.

Back to your questions:

The entire file is read into an IFormFile, which is a C# representation of the file used to process or save the file.

The resources (disk, memory) used by file uploads depend on the number and size of concurrent file uploads. If an app attempts to buffer too many uploads, the site crashes when it runs out of memory or disk space. If the size or frequency of file uploads is exhausting app resources, use streaming.

source 1

The CopyToAsync method enables you to perform resource-intensive I/O operations without blocking the main thread.

source 2

Here you have examples.

Example 1:

using System.IO;
using Microsoft.AspNetCore.Http;
//...

[HttpPost]
[Authorize]
[DisableRequestSizeLimit]
[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]
[Route("upload")]
public async Task<ActionResult> UploadFileAsync(IFormFile file)
{
if (file == null)
return Ok(new { success = false, message = "You have to attach a file" });

var fileName = file.FileName;
// var extension = Path.GetExtension(fileName);

// Add validations here...

var localPath = $"{Path.Combine(System.AppContext.BaseDirectory, "myCustomDir")}\\{fileName}";

// Create dir if not exists
Directory.CreateDirectory(Path.Combine(System.AppContext.BaseDirectory, "myCustomDir"));

using (var stream = new FileStream(localPath, FileMode.Create)){
await file.CopyToAsync(stream);
}

// db.SomeContext.Add(someData);
// await db.SaveChangesAsync();

return Ok(new { success = true, message = "All set", fileName});
}

Example 2 with GridFS:

[HttpPost]
[Authorize]
[DisableRequestSizeLimit]
[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]
[Route("upload")]
public async Task<ActionResult> UploadFileAsync(IFormFile file)
{
if (file == null)
return Ok(new { success = false, message = "You have to attach a file" });

var options = new GridFSUploadOptions
{
Metadata = new BsonDocument("contentType", file.ContentType)
};

using (var reader = new StreamReader(file.OpenReadStream()))
{
var stream = reader.BaseStream;
await mongo.GridFs.UploadFromStreamAsync(file.FileName, stream, options);
}

return Ok(new { success = true, message = "All set"});
}

Upload file into ASP.NET Core Web API

In dotnet core controller you can use IFormFile Interface to get files,

[HttpPost("upload-file")]
public async Task<IActionResult> UploadFile([FromQuery] IFormFile file){

if(file.Length > 0){
// Do whatever you want with your file here
// e.g.: upload it to somewhere like Azure blob or AWS S3
}

//TODO: Save file description and image URL etc to database.
}

In Flutter you need to send a Multipart POST request to include files with binary content (images, various documents, etc.), in addition to the regular text values.

import 'package:http/http.dart' as http;

Future<String> uploadImage(filename, url) async {
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(
http.MultipartFile.fromBytes(
'file',
File(filename).readAsBytesSync(),
filename: filename.split("/").last
)
);
var res = await request.send();
return res;
}

How to upload files with additional file data in asp.net core

If your model is like:

public class Documents
{
public IFormFile documentFile { get; set; }
public string documentVersion { get; set; }
public string documentOperation { get; set; }
}

You can see my test.

Action:

 [HttpPost]
public IActionResult Demo(List<Documents> documents)
{
//...
}

Send data by postman:

Sample Image

Result:

Sample Image

Error 415 while uploading a file through Postman to ASP.NET Core API

If you want to receive IFormFile, you need post content-type=multiple/form-data which is from form data instead of body. Also remember to change [FromBody] to [FromForm].

Postman:
Sample Image

Controller:

[HttpPost]
[Route("{id}")]
public async Task<IActionResult> PostImage([FromForm] IFormFile file, [FromRoute] int id)

{}

If you post file from body, maybe you post a byte array. If though you need change IFormFile file to byte[] file.

.NET Core 6 upload file to wwwroot/images fails sometimes and uploads half images

The CopyToAsync method returns a Task which must be awaited for the copy to succeed. Your code is currently closing the destination stream before the copy completes.

Either change your code to use the synchronous CopyTo method, or make your action method async and await the task.

You'll also want to remove any directory information from the FileName before saving the name to the database - you've done it when you construct the physical path, but not for the Image entity.

And add await using to the DbContext and FileStream instances to ensure they are always disposed of properly.

There's no point storing values in the ViewBag if you're going to return a redirection; those values will always be lost. You could use TempData instead, which would store the messages in the session.

And Directory.GetCurrentDirectory() is not really the best way to get the root path of the application. Instead, inject the IWebHostEnvironment service and use its WebRootPath property to find the physical path of the wwwroot folder.

[HttpPost]
public async Task<IActionResult> UploadFile(IFormFile userfile)
{
await using MgvaKrantransportContext DBContext = new MgvaKrantransportContext();
try
{
string filename = userfile.FileName;
filename = Path.GetFileName(filename);

Image image = new()
{
Filepath = "images/" + filename,
Filename = filename
};

await DBContext.AddAsync(image);
await DBContext.SaveChangesAsync();

string uploadFilePath = Path.Combine(WebHost.WebRootPath, "images", filename);

await using var stream = new FileStream(uploadFilePath, FileMode.Create);
await userfile.CopyToAsync(stream);
}
catch (Exception ex)
{
// TODO: Log the error somewhere
}

return RedirectToAction("Index");
}


Related Topics



Leave a reply



Submit