I'm developing Windows Service that is using FileSystemWatcher to trigger on creation of a new folder. OnCreated it reads a file insp_board.txt that is located in that new folder, logs data into log.txt and waits for another folder creation trigger. When I run code in console app it works fine, but when I run it as a Windows Service it executes OnCreated function properly but on next OnCreated execution it throws IO Exception: Could not access file because it is being used by another process.
Here is the service starting class:
public partial class SPIHydraImport : ServiceBase
{
private SourceWatcher sourceWatcher;
public SPIHydraImport()
{
InitializeComponent();
sourceWatcher = new SourceWatcher();
var eventLogger = new EventLogger("HydraSPIImport", "Application");
}
protected override void OnStart(string[] args)
{
try
{
sourceWatcher.StartWatching();
}
catch (Exception ex)
{
EventLog.WriteEntry("An error occurred: " + ex.Message, EventLogEntryType.Error);
throw;
}
}
protected override void OnStop()
{
sourceWatcher.StopWatching();
}
}
Watcher class:
public class SourceWatcher
{
private FileSystemWatcher watcher;
private Logger logger = new Logger();
private string sourcePath = ConfigurationManager.AppSettings["SourcePath"];
public SourceWatcher()
{
watcher = new FileSystemWatcher();
watcher.Path = sourcePath;
watcher.IncludeSubdirectories = true;
watcher.Filter = "insp_board.txt";
watcher.Created += new FileSystemEventHandler(OnCreated);
watcher.EnableRaisingEvents = true;
}
public void StartWatching()
{
watcher.EnableRaisingEvents = true;
this.logger.LogStandard($"Start: watcher");
}
private void OnCreated(object source, FileSystemEventArgs e)
{
StopWatching();
BoardData boardData = new BoardData();
string directoryPath = e.FullPath;
try
{
this.logger.LogStandard($"{directoryPath}");
boardData = boardData.ParseFile(directoryPath);
this.logger.LogStandard($"BoardID: {boardData.boardId} , Operation: {boardData.operationId} , PCB ID: {boardData.pcbId} , Inspection time: {boardData.inspectionTime} , Tack time: {boardData.tackTime} , Is pass: {boardData.isPass}");
}
catch (Exception exc)
{
this.logger.LogError(exc.ToString());
throw;
}
finally
{
StartWatching();
}
}
public void StopWatching()
{
watcher.EnableRaisingEvents = false;
this.logger.LogStandard("Stop: watcher");
}
}
ParseFile function:
public BoardData ParseFile(string inspBoardPath)
{
var boardData = new BoardData();
var lines = File.ReadAllLines(inspBoardPath).Skip(2);
foreach (var line in lines)
{
var parts = line.Split(',');
boardData.boardId = parts[1];
boardData.operationId = "0" + parts[3];
boardData.pcbId = parts[4];
boardData.inspectionTime = DateTime.ParseExact(parts[5], "yyyyMMddHHmmss", CultureInfo.InvariantCulture).ToString("yyyy-MM-dd HH:mm:ss");
boardData.tackTime = double.Parse(parts[6], CultureInfo.InvariantCulture);
if (parts[7].Equals("3"))
{
boardData.isPass = 1;
} else
{
boardData.isPass = 0;
}
}
return boardData;
}
When running console type application the same error occurred bit I've added watcherEnableRaisingEvents = false: function at the beginning of OnCreated and watcherEnableRaisingEvents = true at the end and it worked fine. Even though I've implemented such solution in Windows Service app it is still causing the same problems. I've also tried to dispose watcher but the result was exactly the same. I've added function checking if the file is existing, and it was existing every time.
public partial class SPIHydraImport : ServiceBasewhy is this partial and what components does it initialize?private Logger logger = new Logger();- let me guess: your own creation?catch (Exception exc) { this.logger.LogError(exc.ToString()); throw; }- why rethrow here? Log, Cleanup, Get on with it.OnCreatedevent is raised, the file it points to not necessarily has been created yet. The process that created it may (you have to assume so) be still writing to it. You should never do anything in those event handlers. Just enqueue the work, so a worker Task / Thread can handle the files it has in the queue (and handles the exceptions) -- Stopping the FSW in the meanwhile is also a bad idea