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:
Result:
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:
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 await
ed 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
C# Version of Java's Synchronized Keyword
Why C# Implements Methods as Non-Virtual by Default
How to Find a Java to C# Converter
How to Use Java-Style Throws Keyword in C#
Extending an Enum via Inheritance
C# Equivalent to Java's Charat()
Is There an Equivalent to the Scanner Class in C# for Strings
Posting JSON to Url via Webclient in C#
ASP.NET Core 6 How to Access Configuration During Startup
How to Exit a Wpf Application Programmatically
Best Way to Read a Large File into a Byte Array in C#
Sqldataadapter VS SQLdatareader