I'm building a file upload web application using ASP.NET Core 6 and I would like the user to be able to confirm whether or not to overwrite an existing file. The application allows for multiple file uploads
Questions:
- where to check if the file exists? (i.e. client-side or on the server)
- if on the client-side how to check if file exists on the server?
- how to handle the POST request so that it can "wait" for user confirmation?
- is this kind of "communication" with the user even possible in ASP.NET Core 6? or should I be using Blazor or Signal R (I'm really new to .NET)
This is my form:
<form method="POST" enctype="multipart/form-data">
<input type="file" multiple name="files">
<button type="submit" >Upload Files</button>
</form>
This is the controller action:
[HttpPost]
public async Task<IActionResult> UploadFiles(IEnumerable<IFormFile> files, string folders)
{
foreach (var file in files)
{
string trimmedFileName = String.Concat(file.FileName.Where(c =>!Char.IsWhiteSpace(c)));
var filePath = Path.Combine(folders, trimmedFileName);
if (System.IO.File.Exists(filePath))
{
ViewBag.Error = $"File {trimmedFileName} already exists on the server";
this.Redirect("UploadFiles");
}
using var filestream = System.IO.File.Create(filePath);
await file.CopyToAsync(filestream);
}
}
I have simplified the above code so as not too add too much detail
Attempts
I have tried AJAX calls to stop the POST request and add some logic but I don't seem to be able to access the folder on the server to even check if the file already exists
$("#uploadForm").submit(function(e){
e.preventDefault();
let files = $(".form-control-file")[0].files;
for (let i = 0; i < files.length; i ){
let url = $("#filePathUrl").val() "/" files[i].name;
if(url){
$.ajax({
url: url,
type: 'HEAD',
error: function(){
alert(files[i].name " exists!");
},
success: function(){
alert(files[i].name " does not exist on server");
I have simplified and removed closing braces from the above code to keep things simple
CodePudding user response:
Your POST to upload the file could return a 409 Conflict status if a file already exists. The UI would then detect this on first posting, and show a popup. If the user selects 'continue', then the POST could include a query parameter to say the user has confirmed the OK is allowed. Something like this:
[HttpPost]
public async Task<IActionResult> UploadFiles(bool? allowOverwrite, IEnumerable<IFormFile> files, string folders)
{
foreach (var file in files)
{
string trimmedFileName = String.Concat(file.FileName.Where(c =>!Char.IsWhiteSpace(c)));
var filePath = Path.Combine(folders, trimmedFileName);
if (!allowOverwrite.GetDefaultValue() && System.IO.File.Exists(filePath)) <---
{
ViewBag.Error = $"File {trimmedFileName} already exists on the server";
return Conflict(); <---
}
using var filestream = System.IO.File.Create(filePath);
await file.CopyToAsync(filestream);
}
}
CodePudding user response:
Here's what you can do,
- Use AjaxRequest to submit the form (by preventing default)
- In Controller Action save files if all the files are new
- Dont save files if there is any duplicate. Send a message to the client stating that these files are duplicate, Do you want to overwrite these files?
- if user says "Yes", send the same AjaxRequest again with an additional parameter and Save all the files (with overwriting duplicate files)
- If user says "No", then nothing needs to be done
Lets move to code
JS
function processFiles(confirmOverwrite = false){
const files = $(".form-control-file")[0].files;
const formData = new FormData();
files.forEach(file => formData,append('files[]', file));
const folderName = 'Uploads';
const url = $("#filePathUrl").val();
$.ajax({
url: url '?folders=' folderName '&confirmOverwrite=' confirmOverwrite,
type: 'POST',
data: formData,
processData: false,
success: (response) =>{
if(response.Status){
alert('Files uploadedn successfully');
}
else{
if(response.Message){
if(confirm(response.Message ' files already exist. Do you want to overwrite these?'){
processFiles(true);
}
else{
alert('Files not uploaded');
}
}
}
},
error: (a,b,c) => {
console.error({a,b,c});
}
});
}
$("#uploadForm").submit(function(e){
e.preventDefault();
processFiles(false);
});
Controller
[HttpPost]
public async Task<IActionResult> UploadFiles(IEnumerable<IFormFile> files, string folders, bool confirmOverwrite = false)
{
var existingFiles = new List<string>();
var filesToBeSaved = new List<(IFormFile file, string filePath)>();
foreach (var file in files)
{
string trimmedFileName = file.FileName.Replace(" ", "");
var filePath = Path.Combine(folders, trimmedFileName);
if (System.IO.File.Exists(filePath) && !confirmOverwrite)
{
existingFiles.Add(file.FileName "(" trimmedFileName ")");
}
else
{
filesToBeSaved.Add((file, filePath));
}
}
if (existingFiles.Any())
{
return Json(new { Status = false, Message = string.Join(", ", existingFiles) });
}
else
{
foreach (var (file, filePath) in filesToBeSaved)
{
using var filestream = System.IO.File.Create(filePath);
await file.CopyToAsync(filestream);
}
return Json(new { Status = true, Message = "Success" });
}
}