3

I have created an ASP.NET web application in which a file needs to be deleted. Below is the code that performs this operation perfectly

File.Delete(path);

However when i tried to do this operation on a background thread like this

Task.Run(() => File.Delete(path));

Then it throws an exception that access to this path is denied. I have tried giving IIS_IUSRS and IUSR full access to the path, but still the error persists. Can someone explain what's going on here. Howcome the file was getting deleted with the first code i.e. on main thread, but not on background thread. Do backgroung threads in C# run with different Identity?

It's a trap
  • 1,333
  • 17
  • 39
  • 3
    Keyword here is the thread pool – L.B Sep 02 '17 at 18:58
  • 2
    After `Task.Run(() => File.Delete(path));` do you something else with the file? Your are not waiting for the Task to finish. If another thread started accessing the file....... – Peter Bons Sep 02 '17 at 18:58
  • @PeterBons No after this point, file is not used at all. That's why we decided to delete it. – It's a trap Sep 02 '17 at 18:59
  • await Task.Run(() => File.Delete(path)); – hugo Sep 02 '17 at 19:00
  • @hugorgor we don't want to await this call. The reason is we don't really care the result of this task very much. However, let me assure you that the behaviour is same irrespective of whether we use await or not. – It's a trap Sep 02 '17 at 19:02
  • Do you leave your controller after this call? – hugo Sep 02 '17 at 19:03
  • @hugorgor no. There are some string manipulations before that. – It's a trap Sep 02 '17 at 19:05
  • How you seen [this](https://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User)? Also your question is [possibly duplicate](https://stackoverflow.com/questions/2608194/how-do-i-start-a-thread-in-a-different-security-context). – Jalal Sep 02 '17 at 19:24
  • Down voters, kindly leave a comment – It's a trap Sep 03 '17 at 08:26

1 Answers1

-2

The main difference between two approaches you provided is that File.Delete(path) calls WinAPI function DeleteFile immediately, and Task.Run(() => File.Delete(path)) does the same with some delay.

Something can happen during this short period of time. E.g. Windows Search service can open file for indexing, antivirus can open file for analysis, or some other process can do something with this (I assume) newly created file.

If you are sure that your application doesn't reopen this file later and doesn't hold file handle anywhere, I recommend to use multiple attempts to avoid such issues:

Task.Run(() =>
{
    const int attemptsNum = 10;
    for (int attempt = 0; attempt < attemptsNum; attempt++)
    {
        try
        {
            File.Delete(path);
            break;
        }
        catch
        {
            if (attempt == attemptsNum - 1)
            {
                throw; // or log exception here
            }
            else
            {
                await Task.Delay(500);
            }
        }
    }
});
  • This will have an adverse effect on application's performance. – It's a trap Sep 03 '17 at 08:28
  • Are you sure this effect is even tangible? We are talking about some milliseconds per file maximum. How many files per second do you expect to be deleted? – Olexiy Sadovnikov Sep 03 '17 at 19:23
  • 1 file per user per every request to that action method. And let me tell you why you were downvoted. If the file gets deleted in the very first iteration, then you will get an exception for the remaining 9 iterations and then every time you will wait for half a second. This way you will end up unnecessarily waiting for about 4-4.5 sec everytime you try to delete the file. Since your threads will be used in this task, less and less threads will be available in the thread pool and will affect scalability. – It's a trap Sep 04 '17 at 10:27
  • Also controlling application flow using exceptions is very bad practice. – It's a trap Sep 04 '17 at 10:28
  • I obviously just forgot to add `break` after `File.Delete(path)`. Fixed. – Olexiy Sadovnikov Sep 04 '17 at 14:26
  • If exception will be fired for every file, you should definitely spend some additional time trying to understand what exact process/thread has an open handle for that file. If it will be fired occasionally, catching it won't be a problem from performance point of view. Also note that I proposed to use `await Task.Delay(500)`, so no thread pool threads are taken while waiting. – Olexiy Sadovnikov Sep 04 '17 at 14:32
  • It's very disappointing when people downvote without giving any better alternative. – Olexiy Sadovnikov Sep 04 '17 at 14:32
  • Yeah it's very disappointing. But if i knew of an answer, i wouldn't have posted the question here. – It's a trap Sep 04 '17 at 15:19