Reputation: 7042
I have implemented a basic logging class and when I try to create a new instance of it, I get the following exception.
The process cannot access the file 'C:\Users\carl\Desktop\My Projects\TCV2\CallPotential.UI\bin\Debug\application.log' because it is being used by another process.
Here is the code for the logger class.
using System;
using System.IO;
using System.Reflection;
namespace CallPotential.Utilities
{
public class Logger : IDisposable
{
/// <summary>
/// Used to write output to the log file.
/// </summary>
private StreamWriter _stream;
/// <summary>
/// The absolute path to the log files location.
/// </summary>
public String LogFileName
{
get
{
// get the directory where our main assembly is located.
Assembly assembly = Assembly.GetExecutingAssembly();
String directoryName = Path.GetDirectoryName(assembly.Location);
return Path.Combine(directoryName, "application.log");
}
}
/// <summary>
/// Creates a new instance of the Logger class
/// </summary>
public Logger()
{
_stream = new StreamWriter(LogFileName);
}
/// <summary>
/// Writes a message out to the application log file.
/// </summary>
/// <param name="message">The message to write to the log file.</param>
public void Write(String message)
{
_stream.WriteLine(message);
_stream.Flush();
_stream.Close();
}
/// <summary>
/// Writes a message including the applications state to the log file.
/// </summary>
/// <param name="state">The application state at the time of the logged message.</param>
/// <param name="message">The message to be written to the log file.</param>
public void Write(AppState state, String message)
{
Write(String.Format("{0}\r\n\t{1}", state, message));
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
if (disposing)
{
if (_stream != null)
{
_stream.Dispose();
_stream = null;
}
}
}
~Logger()
{
Dispose(false);
}
}
}
Note sure why, but it throws the exception in the constructor. Any help figuring this out would be greatly appreciated.
Upvotes: 0
Views: 450
Reputation: 11
You can only have 1 instance of your logger, ever. However, the visual studio application probably is creating an instance via reflection, so it can use intellisense. a) Turn off the hosting process, b) use the command line compile.
To fix your specific problem, however the design is bad.
Upvotes: 0
Reputation: 44921
The basic problem is that you are holding a stream open, which means that you can only ever access one instance of the logging class unless you make some changes.
Various changes that you can make include:
1) Ensure that each instance generates its own log file name.
2) Force all logging to log to a specific file name that is used across the entire application.
In either case, you need to control access to critical functions, such as opening, closing, reading, and writing through SyncLock blocks to ensure that if you are logging from threads or have multiple instance sharing the same file, that only one caller is executing the code simultaneously.
In the first case, you would probably only want to have a single instance.
In the second case, you could use a static streamwriter and static methods since you would not need to create new instances of the class. This is the approach that we implemented many years ago based on guidance from Microsoft in the early exception handling application blocks.
Upvotes: 3
Reputation: 468
I was able to reproduce the error - exception was thrown in the 2nd line:
var logger1 = new Logger();
var logger2 = new Logger();
however when I used Write() method on the first instance, that is:
var logger1 = new Logger();
logger1.Write("XYZ");
var logger2 = new Logger();
the exception wasn't thrown any more. Does it behave the same way in your case?
The problem is that you're using the same file for both loggers and if you don't close the stream or dispose the first instance you're basically trying to have two streams open at the same time for one file.
Try using two different files (e.g. you could pass paths to log files in a constructor instead of having property with default value) and let me know if that solved your problem.
P.S. However, if you need both loggers to write to the same file and they should be able to access the file at the same time then you should take different approach - Singleton pattern would be more appropriate.
Upvotes: 0
Reputation: 2151
I always use the append property for logging so never forget the stream open
public void Write(AppState state, String message)
{
StreamWriter sw = new StreamWriter(LogFileName, true);// true to append the new text
sw.WriteLine(String.Format("{0}\r\n\t{1}", state, message));
sw.Close(); // Close() is the same as Dispose()
}
Upvotes: 0
Reputation: 116108
when I try to create a new instance of it, I get the following exception.
You should dispose your current instance before creating a new instance.
Maybe you should consider singleton pattern.
Upvotes: 1