I'm using log4net in a ASP.NET MVC 4 application and I'm trying to download the generated log file from log4Net.
I have in mind to download the log file with a FileResult, like:
[Authorize(Roles = "Admin")]
public FileResult DownloadUserInterfaceLog()
{
// Get the path of the log file
string path = (LogManager.GetCurrentLoggers()[0].Logger.Repository.GetAppenders()[0] as FileAppender).File;
// Get the file
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
string fileName = "Log.txt";
// Return the expected file
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
My problem is that when I call System.IO.File.ReadAllBytes(path);
I get an Exception, cause the log file is already used by another process.
I'm already put <lockingModel value="log4net.Appender.FileAppender+MinimalLock" /> (which should release the file after any modification) in my Web.Config
with no success.
Begin of log4Net configuration in Web.Config:
<log4net>
<appender name="Appender-root" type="log4net.Appender.RollingFileAppender">
<lockingModel value="log4net.Appender.FileAppender+MinimalLock" />
<file value="Path..." />
<appendToFile value="true" />
Here is an article about similar trouble.
File.ReadAllBytes() function is written such that it uses a call like the following to instantiate a FileStream:
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)
Notice that the FileShare is specified as Read. That means if you have another piece of code writing to the same file at the same time, you will get an error even if the other piece of code created the FileStream by specifying the share mode as “ReadWrite” like so:
FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Solution is to write your own custom ReadAllBytes:
public static byte[] ReadAllBytes(String path)
{
byte[] bytes;
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
int index = 0;
long fileLength = fs.Length;
if (fileLength > Int32.MaxValue)
throw new IOException(“File too long”);
int count = (int)fileLength;
bytes = new byte[count];
while (count > 0)
{
int n = fs.Read(bytes, index, count);
if (n == 0)
throw new InvalidOperationException(“End of file reached before expected”);
index += n;
count -= n;
}
}
return bytes;
}