I call service method using
ThreadPool.QueueUserWorkItem(o => service.Method(arg1, arg2));
Service has object 'loggingService' with I was get using Spring.Net
private readonly ILoggingService loggingService = ObjectBuilder.GetObjectByName("LoggingService");
'LoggingService' class is singleton. It writes log info to log.txt.
When I try to call loggingService.Info("test") in this service method, I get exception: file is busy by another process.
How can I access to the loggingService?
Your singleton is apparently per-thread.
You will need some way of passing the LoggingService
across threads.
For example, you could set service.loggingService
in the original thread.
Alternatively, you might be able to configure Spring.Net to make it a non-thread-local singleton.
Note that your LoggingService must be thread-safe, or you'll get strange errors at runtime.
I had a similar issue while writing some client side application that used a bunch of threads.
Basically you want your LoggingService to keep an internal queue (whose access should be controlled via a lock) and every time you call the log method you only append the message to this queue. At the end of the log method check if the queue is currently being written to a file and if not, start writing.
public static class SingletonLoggingService
{
public static ILoggingService LoggingService = ObjectBuilder.GetObjectByName("LoggingService");
}
SingletonLoggingService.LoggingService.Info("Test");
I did it!
I use Queue and threading:
internal class LoggingService : ILoggingService {
private readonly Queue<LogEntry> queue = new Queue<LogEntry>();
private Thread waiter;
public LoggingService() {
waiter = new Thread(AddLogEntry);
waiter.Start();
}
public void Shutdown() {
try {
waiter.Abort();
} catch {}
}
public void Error(string s, Exception e) {
lock (queue) {
queue.Enqueue(new LogEntry(s, e, LogEntryType.Error));
}
}
public void Warning(string message) {
lock (queue) {
queue.Enqueue(new LogEntry(message, LogEntryType.Warning));
}
}
public void Info(string message) {
lock (queue) {
queue.Enqueue(new LogEntry(message, LogEntryType.Info));
}
}
private void AddLogEntry(object state) {
while (true) {
lock (queue) {
if (queue.Count > 0) {
LogEntry logEntry = queue.Dequeue();
switch (logEntry.Type)
{
case LogEntryType.Error:
logWriter.Error(logEntry.Message, logEntry.Exception);
break;
case LogEntryType.Warning:
logWriter.Warning(logEntry.Message);
break;
case LogEntryType.Info:
logWriter.Info(logEntry.Message);
break;
}
}
}
Thread.Sleep(100);
if (waiter.ThreadState == ThreadState.Aborted) {
waiter = null;
break;
}
}
}
}
I call Shutdown() at the end of app:
protected override void OnExit(ExitEventArgs e) {
loggingService.Shutdown();
base.OnExit(e);
}