If you use the Response.TransmitFile method in your ASP.NET pages, there is a good chance that the file being transmitted is locked and unavailable for writing during that operation. TransmitFile was introduced with .NET V2.0 and it's supposed to be a more optimized version of WriteFile.
For months I had been dogged with exception alerts when a scheduled program was trying to update files used in TransmitFile. As the alerts were intermittent and the files would eventually get updated by the program, I would just ignore the messages. But today I decided to take a closer look and discovered that TransmitFile is to blame for the files being locked.
As I understand, TransmitFile in ASP.NET makes use of the Windows TransmitFile API function which directly streams a file to an open socket. It is more optimized than WriteFile which buffers the entire content of the file before emitting it. In that sense, WriteFile consumes precious memory and processing resources, switching between kernel and user modes, to accomplish its work.
While TransmitFile API function is optimized, care must be taken to avoid having the streamed data getting mixed with other data and my hunch is that some locking mechanism is used to assure an orderly and sequential transmission of data under ASP.NET. That's all fine until one needs to write to the file which could get shot down while the lock is still active. I was able to reproduce this behavior in a loop where a file is continuously updated and then streamed via TransmitFile. Hereβs a simple example:
void Page_Load() {
Response.Buffer=false;
for(;;) {
System.IO.File.WriteAllText(MapPath("/test.txt"), DateTime.Now.ToString());
System.Threading.Thread.Sleep(100);
Response.TransmitFile(MapPath("/test.txt"));
Response.Write("<br>");
}
}
Running this ASP.NET page invariably lead to an exception being thrown. I then changed the code as shown below:
void Page_Load() {
Response.Buffer=false;
for(;;) {
System.IO.File.WriteAllText(MapPath("/test.txt"), DateTime.Now.ToString());
System.Threading.Thread.Sleep(100);
// CHANGED LINE BELOW
Response.Write(System.IO.File.ReadAllText(MapPath("/test.txt")));
Response.Write("<br>");
}
}
I ran the page a number of times and no exception was thrown. I'm sure that ReadAllText is nowhere as optimized as TransmitFile, but I would readily take the performance penalty over the unpredictable exceptions. Incidentally, WriteFile proved to be no better than TransmitFile in locking the file.
Based on the simple test I have concluded that TransmitFile or WriteFile should be used when the file is never or rarely updated. If the file is to be updated frequently, ReadAllText (or other System.IO file reading operations) is the way to go. But if someone can disprove my tenuous theory, by all means.