views:

292

answers:

3

I have a FileUploader control in my web form. If the file being uploaded is already present, I want to delete it, and overwrite it with the newly-uploaded file. But I get an error, as the file is in use by another process, and thus the application can't delete it. Sample code:

if (FUpload.HasFile)
{
    string FileName = Path.GetFileName(FUpload.PostedFile.FileName);
    string Extension = Path.GetExtension(FUpload.PostedFile.FileName);
    string FolderPath = ConfigurationManager.AppSettings["FolderPath"];
    string FilePath = Server.MapPath(FolderPath + FileName);
    if (File.Exists(FilePath))
    {
        File.Delete(FilePath);
    }
    FUpload.SaveAs(FilePath);
}

Is there anything I can do apart from writing the code in try/catch blocks?

+1  A: 

Generate a unique temporary file name. Rename it to your destination when complete. You may still have collisions if someone uploads the "same" file name at the same time. You should always be catching file system errors somewhere. If you don't do it here, may I suggest a global error handler in global.asax.

No Refunds No Returns
A: 

you can save you file with some other name and after that if it exist use File.Replace to replace old file

Utkarsh
I wished I'd said that. :)
No Refunds No Returns
A: 

At the end of the day, due to potential race conditions on your web site (due to, hopefully, concurrent users), you can't get around try/catch. (Why are you averse to it?)

Utkarsh and No Refunds No Returns have the basic answer right -- save it with a temporary file name, then replace/overwrite the existing one if needed. A good approach for this is to use a GUID as the temporary file name, to ensure that there are no collisions on the filename alone.

Depending on the nature of your application, you could get quite a few files stacked up, uploaded by different users, with lots of potential name conflicts. Depending on the nature and scale of your app, as well as its security boundaries, you might consider giving each user his/her own directory, based on user ID (how you'd identify the user in the database). Each user uploads his/her files there. If there's a name collision, you can bounce back to the user (holding the GUID name in session if needed) and ask if he/she wants to overwrite, and know with confidence that the answer is safe.

  • If the user declines to overwrite, you can delete your temp file.
  • If the user agrees to overwrite, you can delete the original and write the new one.
  • In either event, all of this is localized to the user's own directory, and thus (unless multiple users are signed on with the same ID) the behavior is safe.

In general, this will be more robust and safe than arbitrarily overwriting file name collisions.

Again, due to race conditions and other situations beyond your control, you need to use a try/catch block any time you attempt to write to the file system. Why? What if the drive is out of space? What if the file you are attempting to overwrite is legitimately in use by another process? What if the file you are attempting to overwrite has NTFS permissions forbidding the web process from touching it? So on and so forth. You need to be prepared to handle these kinds of exceptions.

John Rudy