0

Why, after this code executes, can I not manually delete the generated file? I get this error message:

The action can't be completed because the file is open in IIS Express Workers Process.

The code:

System.IO.File.AppendAllText("Filename.txt", "Some Text");

The application is a web application and running in IIS. My understanding was AppendAllText automatically closes the file handle.

I am not using this code to log. The purpose of the code is to create a CSV file that is then attached to an email. If I execute the code and email the file, the file is never sent. If I then restart IIS (to release the lock) and execute only the code to mail the file (no generation), it works.

The code to attach the file...

SmtpClient mailClient = new SmtpClient();
MailMessage msg = new MailMessage();
... Add From, Subject, Body, etc... here
msg.Attachments.Add(new Attachment(filename));
mailClient.Send(msg);

No exceptions are thrown, nothing is written to the log file indicating problems. The email is simply not sent and if I go to the generated file and attempt to delete it, I cannot as IIS has it locked. I believe the lock is why the email is never sent.

birwin
  • 2,524
  • 2
  • 21
  • 41
  • Can you show the whole code where you get text, append this text and delete this file? – Yeldar Kurmangaliyev Aug 07 '18 at 14:33
  • 2
    Just in case if you are going to use `AppendAllText` to actually log messages - **don't**. – Yeldar Kurmangaliyev Aug 07 '18 at 14:34
  • 1
    `AppendAllText` will only lock the file while *writing* to it. In a web application though, a *lot* of requests may be writing at any time. Which is why creating a logging library is *not* easy. – Panagiotis Kanavos Aug 07 '18 at 14:34
  • 1
    Are you concurrently accessing the file? – jAC Aug 07 '18 at 14:34
  • 1
    There are a *lot* of great logging libraries that handle concurrent logging, rolling files, deletions, retention. Use one of them, eg Serilog, NLog or log4net – Panagiotis Kanavos Aug 07 '18 at 14:35
  • I appreciate everyone's comments. I am not using this code to log. I have updated the question with more details. Also, I am not concurrently accessing the file that I am aware of. – birwin Aug 07 '18 at 15:08

1 Answers1

1

File.AppendAllText close the file itself after writing it. But you are facing the issue probably because the file is shared across multiple session in your web application. Use lock to prevent concurrent access.

You should handle the code you provided in a different way for web application.

using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
    System.IO.StreamWriter writer = new System.IO.StreamWriter(ms);
    writer.Write("Some Text");
    writer.Flush();
    writer.Dispose();
    ms.Position = 0;

    System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);
    System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct);
    attach.ContentDisposition.FileName = "Filename.txt";

    SmtpClient mailClient = new SmtpClient();
    MailMessage msg = new MailMessage();
    msg.Attachments.Add(attach);
    mailClient.Send(msg);
}

In the above example attachment is created in-memory insteed of storing in file-system.

Rajib Dey
  • 54
  • 4
  • It sounds like you are suggesting `System.IO.File.AppendAllText` should not be used for web appliications? – birwin Aug 07 '18 at 15:28
  • 1
    No, this workaround is ignoring the root problem: disposable objects MUST be disposed. In this case both `SmptClient` and `MailMessage`. More than that this approach with `StreamWriter` is **wrong**, if `Write()` fails for any reason (running out of memory? file too big?) then you're relying on an implementation detail: `StreamWriter` does not hold any resource (your `Dispose()` isn't called). Another implementation detail: you can still use a `MemoryStream` after it has been disposed (it's what, by default, `StreamWriter.Dispose()` does on the outer stream). – Adriano Repetti Aug 07 '18 at 15:36
  • Adriano's comment got me pointed in the right direction. The fact that email messages were sent after restarting IIS had me believing the issue was not with the SendMail code. I was wrong. Apparently the combination of creating the file and then emailing it caused the send to fail unless the attachments and the client were disposed after the send command was issued. Thank you to all who helped. StackOverflow is a great platform because of everyone's efforts. – birwin Aug 07 '18 at 16:55