Logging best approaches - c#

I'm preparing to start developing a new application which has to connect to different API's of different machines which will make the application fairly complicated.
What approaches are there to implement logging into my application, and what are their respective advantages and disadvantages? To be more precise, I'm looking into the best way to export the logs to an external logfile.
Details:
Currently I'm using a system where I add a logentry to a list of logs which I then process line by line through a backgroundworker.
My idea behind this is that by putting the logsprocessing on a different thread I will not disturb the main UI-thread or any other threads for that matter.
However, I think that I'm still using unnecessary resources in my UI-thread because I'm compiling and adding my logentry on the UI-thread. Should I put the actual entry as well on a different thread?
Here is the code that I currently use:
List<LoggingClass> Logs;
BackgroundWorker bgLogs;
public void startLogging()
{
// INITIALIZE THE BACKGROUND WORKER
bgLogs = new BackgroundWorker();
// SET UP THE BACKGROUND WORKER
bgLogs.WorkerSupportsCancellation = true;
bgLogs.WorkerReportsProgress = false;
bgLogs.DoWork += bgLogs_DoWork;
// START THE BACKGROUND WORKER
bgLogs.RunWorkerAsync();
}
private void bgLogs_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (worker.IsBusy == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
if (Logs != null && Logs.Count > 0)
{
processLogs();
}
Thread.Sleep(1000);
}
}
}
public void log(DateTime logTimeStamp, LogType logType, string logContent)
{
// CHECK IF THE LIST OF LOGS EXISTS
if (Logs == null)
{
Logs = new List<LoggingClass>();
}
// CREATE A TEMPORARY LOG ENTRY
LoggingClass tmpLog = new LoggingClass();
tmpLog.TimeStamp = logTimeStamp;
tmpLog.Type = logType;
tmpLog.Content = logContent;
// ADD THE LOG TO THE LIST OF LOGS
Logs.Add(tmpLog);
// CLEAR THE TEMPRARY LOG
tmpLog = null;
}
private void processLogs()
{
string logOutput = string.Empty;
do
{
// CREATE A TEMPORARY LOG ENTRY
LoggingClass tmpLog = Logs[0];
// APPEND THE LOG DATA INTO THE TEMPORARY STRING
logOutput += string.Format("[{0}]\t{1}\t{2}", tmpLog.TimeStamp.ToString("HH:mm:ss.fff"), tmpLog.Type.ToString(), tmpLog.Content) + Environment.NewLine;
// REMOVE THE FIRST LOG ENTRY
Logs.RemoveAt(0);
} while (Logs.Count > 0);
// GET THE FILENAME FOR THE LOGGING FILE
DateTime currentDate = DateTime.Now;
string logFile = Path.GetFullPath(Path.Combine(Application.ExecutablePath, #"..\LOGS\" + currentDate.ToString("yyyyMMdd") + "_log.log"));
// CHECK AND CREATE IF NEEDED THE LOGS DIRECTORY
Directory.CreateDirectory(Path.GetDirectoryName(logFile));
// ADD THE LOGGINGCONTENT TO THE LOG FILE
File.AppendAllText(logFile, logOutput, Encoding.UTF8);
}
class LoggingClass
{
public DateTime TimeStamp { get; set; }
public LogType Type { get; set; }
public string Content { get; set; }
}
Are there any issues with using this method?

Related

Windows Service: The calling thread cannot access this object because a different thread owns it

Trying to convert XML files using XSL and printing the output. However, receiving the following message: The calling thread cannot access this object because a different thread owns it.
To set an interval for checking files, added a timer to the OnStart.
if (findPrinter() > 0)
{
System.Timers.Timer printNetterCheck = new System.Timers.Timer();
printNetterCheck.Elapsed += new ElapsedEventHandler(OnTimedEvent);
printNetterCheck.Interval = 30000;
printNetterCheck.Enabled = true;
}
The OnTimedEvent:
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
getFiles();
}
If any files available, call print:
foreach (string file in files)
{
try
{
StringWriter xslTransformResult = new StringWriter();
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xslPath);
xslt.Transform(file, null, xslTransformResult);
if (print(xslTransformResult) == 1)
{
//do some things
The print function:
private int print(StringWriter transformedXML)
{
//assume OK
int rc = 1;
try
{
StringReader printNetterStreamReader = new StringReader(transformedXML.ToString());
PrintSystemJobInfo printNetterJob = printer.AddJob("PrintNetterPrint");
Stream printNetterStream = printNetterJob.JobStream;
Byte[] printNetterByteBuffer = UnicodeEncoding.Unicode.GetBytes(printNetterStreamReader.ReadToEnd());
printNetterStream.Write(printNetterByteBuffer, 0, printNetterByteBuffer.Length);
printNetterStream.Close();
}
catch (Exception e)
{
//return fail
rc = -1;
eventLog.WriteEntry("Error printing: " + e.Message, EventLogEntryType.Error);
}
return rc;
}
When calling print I receive the thread error. Found some stuff about Dispatchers etc.. but those are not available when using services.
Check PrintQueue.AddJob.
The method makes a COM call which requires the application be running in a single apartment (STA). The easiest way to fix that is to add STAThreadAttribute to Main which will force the application to run in a single thread. If you need multithreading in your application then you will need to implement the necessary plumbing to run the PrintQueue separately on an STA Thread.
// Create a factory to hold your printer configuration
// So that it can be retrieved on demand
// You might need to move the findPrinter() logic
public class PrintQueueFactory
{
private static PrintQueue _instance = new PrinterQueue(/* Details */);
public static PrintQueue PrintQueue { get { return _instance; } }
}
private int print(StringWriter transformedXML)
{
//assume OK
int rc = 1;
try
{
var printer = PrintQueueFactory.PrintQueue;
var staThread = new Thread(() => Print(printer, transformedXML.ToString()));
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
}
catch (Exception e)
{
//return fail
rc = -1;
eventLog.WriteEntry("Error printing: " + e.Message, EventLogEntryType.Error);
}
return rc;
}
private static void Print(PrintQueue printer, string lines)
{
using(var printNetterJob = printer.AddJob("PrintNetterPrint"))
using(var printNetterStreamReader = new StringReader(lines))
using(var printNetterStream = printNetterJob.JobStream)
{
Byte[] printNetterByteBuffer = UnicodeEncoding.Unicode.GetBytes(printNetterStreamReader.ReadToEnd());
printNetterStream.Write(printNetterByteBuffer, 0, printNetterByteBuffer.Length);
}
}
maybe, as you are using a Timer control, it is related with multi-threading, maybe you should check if an Invoke is Required (InvokeRequired) in the Timer.Elapsed event handler.
If so, you should create a delegate to call this function, so it can be executed in the right thread.
Check this Invoke-Required question

Control.BeginInvoke does not call delegate when UI function is idle

I am modifying a windows desktop application that works with some external hardware. When the user activates the hardware from the application a progress (UI) form is started. This form creates a thread that performs all of the work with the hardware. The problem comes when I try to report progress back to the UI thread. It appears that the first of my Control.BeginInvoke ("Negotiating message") works fine. However, the second one (first adjustment to progressbar) never seems to call it's delegate and as a result the application locks up on the subsequent endinvoke. I believe the issue is that the GUI is now in an idle state, but I am not sure how to fix the situation. Any help would be appreciated. Code found below:
In the UI Load Method Thread:
private void frmTwainAquire_Load(object sender, EventArgs e)
{
try
{
//Show the GUI
this.Visible = showGUI;
pbScanningProgress.Value = 0;
btnCancel.Enabled = false;
btnCancel.Visible = false;
// Set the delegates.
SetScanMessageDelegate = new SetScanMessage(this.SetScanMessageMethod);
SetRegistrationMessageDelegate = new SetRegistrationMessage(this.SetRegistrationMessageMethod);
AddScanProgressDelegate = new AddScanProgress(this.AddScanProgressMethod);
AddRecogProgressDelegate = new AddRecogProgress(this.AddRecogProgressMethod);
// Set progress bars.
pbScanningProgress.Value = 0;
pbRecognition.Value = 0;
abortScan = false;
// Create thread here!
twainInstance = new rScan.Twain();
rScanning = new rScanThread(this, twainInstance);
// Start the thread.
rScanning.tScan = new Thread(rScanning.Scan);
rScanning.tScan.Start();
}
catch (Exception ex)
{
// Error checking here.
}
}
Delegate Methods:
public void SetScanMessageMethod(string scanMessage)
{
this.lblScanMessage.Text = scanMessage;
}
public void SetRegistrationMessageMethod(string recogMessage)
{
this.lblRecognition.Text = recogMessage;
}
public void AddScanProgressMethod(int progress)
{
this.pbScanningProgress.Value += progress;
}
public void AddRecogProgressMethod(int progress)
{
this.pbRecognition.Value += progress;
}
Thread method that is giving the problem. Please note that the thread is in a different class then the previous two code blocks (both are in the UI class):
public class rScanThread : IMessageFilter
public void Scan()
{
// Set progress bar message.
IAsyncResult result;
if (frmTwainAquireInstance.lblScanMessage.IsHandleCreated && frmTwainAquireInstance.lblScanMessage.InvokeRequired)
{
result = frmTwainAquireInstance.lblScanMessage.BeginInvoke(frmTwainAquireInstance.SetScanMessageDelegate, "Negotiating Capabilities with Scanner.");
frmTwainAquireInstance.lblScanMessage.EndInvoke(result);
}
else
{
frmTwainAquireInstance.lblScanMessage.Text = "Negotiating Capabilities with Scanner.";
}
// Start the intialization of the rScan process.
bool intializeSuccess = twainInstance.Initialize(frmTwainAquireInstance.Handle);
// If the process could not be started then quit.
if (!intializeSuccess)
{
frmTwainAquireInstance.Close();
return;
}
if (frmTwainAquireInstance.pbScanningProgress.IsHandleCreated && frmTwainAquireInstance.pbScanningProgress.InvokeRequired)
{
result = frmTwainAquireInstance.pbScanningProgress.BeginInvoke(frmTwainAquireInstance.AddScanProgressDelegate, 33);
frmTwainAquireInstance.pbScanningProgress.EndInvoke(result); // Lock up here.
}
else
{
frmTwainAquireInstance.pbScanningProgress.Value += 33;
}
// Do more work after. The code never makes it this far.
} // End of rScanThread.Scan()

detect selected program opened using openas_rundll in c#

I am opening a file using openfile dialog with the help of openas_rundll in c#.
Process.Start("rundll32.exe", string.Format("shell32.dll,OpenAs_RunDLL \"{0}\"", tempFilePath));
Now I want to detect which program is used to open the file. I want to trace the process.
My goal is to delete the file when user close the program.
You can try to catch the moment when actual app is closed by finding it py parent process id. If you found it, you can wait it to close as long as it is acceptable. Thanks jeremy-murray for GetAllProcessParentPids method:
public void StartProcessAndWathTillTerminated(string tempFilePath)
{
// Show app selection dialog to user
Process rundll32 = Process.Start("rundll32.exe", string.Format("shell32.dll,OpenAs_RunDLL {0}", tempFilePath));
int rundll32id = rundll32.Id;
// Wait till dialog is closed
while (!rundll32.HasExited)
{
System.Threading.Thread.Sleep(50);
}
// Get all running processes with parent id
Dictionary<int, int> allprocparents = GetAllProcessParentPids();
int openedAppId = 0;
// Loop throu all processes
foreach (var allprocparent in allprocparents)
{
// Found child process, started by our rundll32.exe instance
if (allprocparent.Value == rundll32id)
{
openedAppId = allprocparent.Key;
break;
}
}
// Check if we actually found any process. It can not be found in two situations:
// 1) Process was closed too soon, while we was looking for it
// 2) User clicked Cancel and no application was opened
// Also it is possible that chesen application is already running. In this
// case new instance will be opened by rundll32.exe for a very short period of
//time needed to pass file path to running instance. Anyway, this case falls into case 1).
//If we ca not find process explicitly, we can try to find it by file lock, if one exists:
//I'm using here a code snippet from https://stackoverflow.com/a/1263609/880156,
//which assumes that there are possible more than one lock on this file.
//I just take first.
if (openedAppId==0)
{
Process handleExe = new Process();
handleExe.StartInfo.FileName = "handle.exe";
handleExe.StartInfo.Arguments = tempFilePath;
handleExe.StartInfo.UseShellExecute = false;
handleExe.StartInfo.RedirectStandardOutput = true;
handleExe.Start();
handleExe.WaitForExit();
string outputhandleExe = handleExe.StandardOutput.ReadToEnd();
string matchPattern = #"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach(Match match in Regex.Matches(outputhandleExe, matchPattern))
{
openedAppId = int.Parse(match.Value);
break;
}
}
if (openedAppId != 0)
{
Process openedApp = Process.GetProcessById(openedAppId);
while (!openedApp.HasExited)
{
System.Threading.Thread.Sleep(50);
}
}
// When we reach this position, App is already closed or was never started.
}
public static Dictionary<int, int> GetAllProcessParentPids()
{
var childPidToParentPid = new Dictionary<int, int>();
var processCounters = new SortedDictionary<string, PerformanceCounter[]>();
var category = new PerformanceCounterCategory("Process");
// As the base system always has more than one process running,
// don't special case a single instance return.
var instanceNames = category.GetInstanceNames();
foreach(string t in instanceNames)
{
try
{
processCounters[t] = category.GetCounters(t);
}
catch (InvalidOperationException)
{
// Transient processes may no longer exist between
// GetInstanceNames and when the counters are queried.
}
}
foreach (var kvp in processCounters)
{
int childPid = -1;
int parentPid = -1;
foreach (var counter in kvp.Value)
{
if ("ID Process".CompareTo(counter.CounterName) == 0)
{
childPid = (int)(counter.NextValue());
}
else if ("Creating Process ID".CompareTo(counter.CounterName) == 0)
{
parentPid = (int)(counter.NextValue());
}
}
if (childPid != -1 && parentPid != -1)
{
childPidToParentPid[childPid] = parentPid;
}
}
return childPidToParentPid;
}
Update
It seems that there is no solution with 100% guarantee of success due to many reasons.
I think that finding a process started by rundll32.exe is most solid among all other. If it fails, you still able to complete it with some other methods to determine process id.
As far as i know, there are several other ways to find that file is still used. Winword.exe, for example, creates some temp files in same directory and removes them when it closes. So if you able to catch a moment of temp files deleting then you may assume that program been closed.
Other programs may hold your file open by setting a lock on it. If so, you can find that program by finding lock owner. I used a solution with external program handle.exe from this answer https://stackoverflow.com/a/1263609/880156, so take a look.
I have to mention, that there may be no permanent file lock at all. It depend on program architecture. For example, if you open html file with Firefox, it reads file as fast as it can and closes it and does not leave file locked no more. In this case, even if you somehow find process name (e.g. "firefox.exe"), you will not able to find a moment when user closes a tab with your file.
If i were you, i would implement this solution, that still not ideal, and i would updgrade it later if it is necessary.
Just a simple helper class which provides you with a method to open a file with the OpenWithDialog of windows and monitors the started processes with WMI to identify the choosen application.
for WMI, add System.Management.dll as reference
NOTICE: It doesn't recognice windows photo viewer
- which is a dllhost.exe
Example call for your situation:
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Filter = "All files(*.*)|*.*";
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
using (Win.OpenWithDialogHelper helper = new Win.OpenWithDialogHelper())
{
helper.OpenFileAndWaitForExit(ofd.FileName);
File.Delete(helper.Filepath);
}
}
}
The class:
namespace Win
{
using System.Management;
using System.Threading;
using System.Diagnostics;
using System.IO;
public class OpenWithDialogHelper : IDisposable
{
#region members
private Process openWithProcess;
private ManagementEventWatcher monitor;
public string Filepath { get; set; }
public Process AppProcess { get; private set; }
#endregion
#region .ctor
public OpenWithDialogHelper()
{
}
public OpenWithDialogHelper(string filepath)
{
this.Filepath = filepath;
}
#endregion
#region methods
public void OpenFileAndWaitForExit(int milliseconds = 0)
{
OpenFileAndWaitForExit(this.Filepath, milliseconds);
}
public void OpenFileAndWaitForExit(string filepath, int milliseconds = 0)
{
this.Filepath = filepath;
this.openWithProcess = new Process();
this.openWithProcess.StartInfo.FileName = "rundll32.exe";
this.openWithProcess.StartInfo.Arguments = String.Format("shell32.dll,OpenAs_RunDLL \"{0}\"", filepath);
this.openWithProcess.Start();
//using WMI, remarks to add System.Management.dll as reference!
this.monitor = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
this.monitor.EventArrived += new EventArrivedEventHandler(start_EventArrived);
this.monitor.Start();
this.openWithProcess.WaitForExit();
//catching the app process...
//it can't catched when the process was closed too soon
//or the user clicked Cancel and no application was opened
Thread.Sleep(1000);
int i = 0;
//wait max 5 secs...
while (this.AppProcess == null && i < 3000)
{
Thread.Sleep(100); i++;
}
if (this.AppProcess != null)
{
if (milliseconds > 0)
this.AppProcess.WaitForExit(milliseconds);
else
this.AppProcess.WaitForExit();
}
}
public void Dispose()
{
if (this.monitor != null)
{
this.monitor.EventArrived -= new EventArrivedEventHandler(start_EventArrived);
this.monitor.Dispose();
}
if(this.openWithProcess != null)
this.openWithProcess.Dispose();
if (this.AppProcess != null)
this.AppProcess.Dispose();
}
#endregion
#region events
private void start_EventArrived(object sender, EventArrivedEventArgs e)
{
int parentProcessID = Convert.ToInt32(e.NewEvent.Properties["ParentProcessID"].Value);
//The ParentProcessID of the started process must be the OpenAs_RunDLL process
//NOTICE: It doesn't recognice windows photo viewer
// - which is a dllhost.exe that doesn't have the ParentProcessID
if (parentProcessID == this.openWithProcess.Id)
{
this.AppProcess = Process.GetProcessById(Convert.ToInt32(
e.NewEvent.Properties["ProcessID"].Value));
if (!this.AppProcess.HasExited)
{
this.AppProcess.EnableRaisingEvents = true;
}
}
}
#endregion
}
}

C# Making a program finish processes before advancing

In C#, how do you make a program only process one thing at a time? I've been working on a patching system, and I think I have the coding all correct but can't test it because a lot of the functions are trying to process all at once when they need to be processing in an order. The program doesn't even let the display shown up before it starts trying to process everything. Because none of them return a value other then the main function all the functions are set to void. I thought about maybe using a return value inside of a loop to make sure the program is finished with that step first before moving on but it still leaves the problem of the program not even showing up until everything is done processing which its suppose to show the progress of everything. Any suggestions of tips?
Edit: I don't know what to post in the code, so im posting all the main functions:
public void DSP_Load(object sender, EventArgs e)
{
if (v1 >= v2)
{
File_Progress_Title.Text = "100%";
Update_Status.Text = "Divine Shadows is currently up to date.";
Application.DoEvents();
Process.Start("Divine Shadows.exe");
Close();
}
else
{
Update_Status.Text = "Checking For Updates...";
Application.DoEvents();
if (!Directory.Exists(tempFilePath))
{
Directory.CreateDirectory(tempFilePath);
}
using (SqlCon = new MySqlConnection(connString))
{
SqlCon.Open();
string command = "SELECT * FROM version where version > '" + v1 + "' ORDER BY version LIMIT 1";
MySqlCommand GetLatestVersion = new MySqlCommand(command, SqlCon);
using (MySqlDataReader DR = GetLatestVersion.ExecuteReader())
{
while(DR.Read())
{
do
{
string LatestVersion = Convert.ToString(DR.GetValue(1));
string WebURL = Convert.ToString(DR.GetValue(2));
update.DownloadFileAsync(new Uri(WebURL), tempFilePath + "patch" + LatestVersion + ".zip");
update.DownloadProgressChanged += new DownloadProgressChangedEventHandler(download);
update.DownloadFileCompleted += new AsyncCompletedEventHandler(extration);
Application.Restart();
}
while (v1 < v2);
Process.Start("Divine Shadows.exe");
Close();
}
}
}
}
}
public void download(object sender, DownloadProgressChangedEventArgs e)
{
if (v1 >= v2)
{
File_Progress_Title.Text = "100%";
Update_Status.Text = "Divine Shadows is currently up to date.";
Application.DoEvents();
Process.Start("Divine Shadows.exe");
Close();
}
else
{
Update_Status.Text = "Downloading Updates...";
Application.DoEvents();
File_Progress_Display.Value = e.ProgressPercentage;
File_Progress_Title.Text = Convert.ToString(e.ProgressPercentage) + "%";
}
}
public void extration(object sender, AsyncCompletedEventArgs e)
{
if (v1 >= v2)
{
File_Progress_Title.Text = "100%";
Update_Status.Text = "Divine Shadows is currently up to date.";
Application.DoEvents();
Process.Start("Divine Shadows.exe");
Close();
}
else
{
Update_Status.Text = "Installing Updates, Please Wait...";
Application.DoEvents();
UnzipFile(extactFile, extractLocation);
}
}
public static void UnzipFile(string extactFile, string extractLocation)
{
try
{
FastZip fastZip = new FastZip();
fastZip.CreateEmptyDirectories = false;
fastZip.ExtractZip(extactFile, extractLocation, FastZip.Overwrite.Always, null, null, null, false);
}
catch (Exception ex)
{
throw new Exception("Error unzipping file \"" + extactFile + "\"", ex);
}
File.Delete(extactFile);
}
Your problem is not WebClient() specific, its about how your application is working with threads.
In general, winforms applications have one GUI Thread. This thread is used to executed your methods and also updating the user interface. If you start a long term process, the gui thread gets locked till the operation is finished. Thats the reason why your display is not shown.
You can solve that problem by implementing the BackgroundWorker. On that website you can also find an example how to implement it. Let the BackgroundWorker do your patching process and use events inside the BackgroundWorker.RunWorkerAsync() method to update your GUI.
If you are using c#4 or newer you can use the Task Parallel Library to perform tasks asynchronously, thus leaving your UI response while thing are being downloaded. First of all you need a reference:
using System.Threading.Tasks;
And some code:
public void YourMainFunction()
{
var urls = new List<string>();
urls.Add("http://google.com");
urls.Add("http://yahoo.com");
foreach(var url in urls)
{
Task.Factory.StartNew<DownloadResult>(() =>
DownloadIt(url))
.ContinueWith(WorkDone, TaskScheduler.FromCurrentSynchronizationContext());
}
}
private class DownloadResult
{
public string Url {get; set;}
public string Result {get; set;}
}
private DownloadResult DownloadIt(string url)
{
var downloadResult = new DownloadResult{ Url = url };
var client = new WebClient();
downloadResult.Result = client.DownloadString(url);
return downloadResult;
}
private void WorkDone(Task<DownloadResult> task)
{
if(task.IsFaulted)
{
//An exception was thrown
MessageBox.Show(task.Exception.ToString());
return;
}
//Everything went well
var downloadResult = task.Result;
//Here you can update your UI to reflect progress.
MessageBox.Show(downloadResult.Result);
}

How to implement both the FileSystemWatcher and Timer in Multithreading in C# console application?

I need to create a C# Console Application that will parse the file from SFTP directory when the new file created. For that I implemented FileSystemWatcher with FileCreated event which enqueue the new file path and create a new thread and parse the file.
I read in the blogs that some times FileSystemWatcher may fail to detect new files, for that I implemented Timer which will fire every 1 hr and if the FileSystemWatcher thread is in waitsleep state then will read the IMCOMING SFTP folder and parse the file.
Below is the code i written for FileSystemWatcher and Timer, but its not working properly and I think filesystemwatcher is not in Multithreading. Please help me to get right solution.
MAIN
static void Main(string[] args)
{
try
{
string path = incomingFilePath;
if (Directory.Exists(path))
{
#region Initiate Timer
Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));
t.Start((Action)fileProcessor.StartTimer);
#endregion
#region FileSystemWatcher
watcher = new FileSystemWatcher { Path = path, Filter = "*.CUST", IncludeSubdirectories = true };
watcher.Created += new
FileSystemEventHandler(watcher_FileCreated);
watcher.Error += new
ErrorEventHandler(watcher_OnError);
watcher.EnableRaisingEvents = true;
#endregion
}
}
catch (Exception Err)
{
}
}
FILESYSTEMWATCHER CODE:
private static void watcher_FileCreated(object sender, FileSystemEventArgs e)
{
if (e.FullPath.ToUpper().Contains("INCOMING"].ToString()))
{
fileProcessor.EnqueueFile(e.FullPath);
lock (lockObject)
{
files.Enqueue(path);
}
if (FileWacherThread == null || shouldStop)
{
FileWacherThread = new Thread(new ThreadStart(Work));
FileWacherThread.Start();
}
// If the thread is waiting then start it
else if (FileWacherThread.ThreadState == ThreadState.WaitSleepJoin)
{
waitHandle.Set();
}
}
}
private void Work()
{
while (!shouldStop)
{
string path = String.Empty;
lock (lockObject)
{
if (files.Count > 0)
{
path = files.Dequeue();
}
}
if (!String.IsNullOrEmpty(path))
{
// Process the file
ParseFile(path);
}
else
{
// If no files are left to process then wait
waitHandle.WaitOne();
}
}
}
TIMER CODE
public void StartTimer()
{
lock (lockObject)
{
if (FileWacherThread == null || FileWacherThread.ThreadState == ThreadState.WaitSleepJoin)
{
if (files.Count == 0)
{
IEnumerable<string> result = new List<string>(Directory.GetFiles(incomingFilePath, "*.CUST", SearchOption.AllDirectories)).Where(s => s.Contains(incomingFilePrefix));
foreach (string path in result)
{
ParseFile(path);
}
}
}
}
}
Things to check...
is waitHandle an AutoResetEvent or a ManualResetEvent? (from the way that you are using it, it should be an AutoResetEvent
If shouldStop is true, is FileWacherThread(sic) set to null when Work() exits...
How are you protecting access to FileWacherThread? if it is accessed from multiple threads (to check its state, assign etc, then it too should be protected with a lock).
You shouldn't worry about the state of the FileWacherThread when you set the event. If you want to signal to that thread, just set it, (i.e. build your multithreaded code such that the publisher doesn't know/care about the current state of the subscriber).
Currently there are states that your FileWacherThread can be in where it isn't waiting but it might still need to be signaled. If you always set the event, the worst that can happen is that it loops one time unnecessarily.

Categories

Resources