System.IO.IOException: The process cannot access the file ".txt" because it is in use by another process
I am using the following code to log web application errors.
using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
{
myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
}
Sometimes, the following exception is "System.IO.IOException: The process cannot access the file" .txt "because it is being used by another process." rushes.
I think this is caused by multiple instances of the web application at the same time. Can you help me fix this issue please?
EDIT: I must add that for each method I write like this:
Date - Method X started.
Date - Exception.Message (table not found or other errors)
Date - Method X stopped.
and when this error appears, it only logs this:
Date - System.IO.IOException: The process cannot access the file ".txt" because it is in use by another process.
source to share
I added this code to my class:
public static bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch
{
return true;
}
finally
{
if (stream != null)
{
stream.Close();
}
}
return false;
}
and now my LogToFile method looks like this:
while (IsFileLocked(fi))
{
}
using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
{
if (displayTime == true)
myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10}{3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
else
myStream.WriteLine(string.Format("{0, -70}{1, -10}{2} ", guid, StringEnum.GetStringValue(enumMsg), sText));
}
I hope this works.
source to share
Sadly, Windows doesn't let you wait for a file lock. To get around this, all your applications will need to create a lock that all processes can check.
Using this code will prevent threads within the same process from accessing the file:
/* Suitable for a single process but fails with multiple processes */
private static object lockObj = new Object();
lock (lockObj)
{
using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
{
myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
}
}
Locking multiple processes requires locking Mutex. This gives a name to the lock that other processes can check. It works like this:
/* Suitable for multiple processes on the same machine but fails for
multiple processes on multiple machines */
using (Mutex myMutex = new Mutex(true, "Some name that is unlikly to clash with other mutextes", bool))
{
myMutex.WaitOne();
try
{
using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
{
myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
}
}
finally
{
myMutex.ReleaseMutex();
}
}
I don't think Mutexes have access from remote computers, so if you have a file in a file share and are trying to write it from processes on multiple computers, you are probably better off writing a server component to the machine that hosts file for mediation between processes.
source to share
Assuming you want each thread to end up being logged, you could block the critical section
private static object fileLock = new Object();
...
lock (fileLock)
{
using (StreamWriter myStream = new StreamWriter(sLogFilePath, true))
{
myStream.WriteLine(string.Format("{0, -45}{1, -25}{2, -10 {3}", guid, DateTime.Now, StringEnum.GetStringValue(enumMsg), sText));
}
}
This means that only one thread at any given time can write to the file, other threads are blocked until the current thread exits the critical section (at this moment the file lock will be removed).
It should be noted that it lock
works per process, so if your site is using a web farm / garden context you will need to look at the system blocking mechanism i.e. Mutexes .
source to share
Your web server will run requests on multiple threads. If two or more queries need to log exceptions at the same time, this will result in the exception you are seeing.
You can lock the section, as James suggested, or you can use a registration framework that will handle multithreading issues for you, like Lgo4net or NLog .
source to share