How to debug FileSystemWatcher c# - filesystemwatcher

Can someone explain how I debug this?
I have built a windows service which monitors a folder and when a file is created in that folder, it moves that newly created file to another folder. Pretty simple and works. I am trying to pad it out now with out features and I'm starting to get generic IOExpections thrown in event viewer, so I want to try and debug. But the issue I am having is when to create the new file in the directory during debugging.
This is my code so far
which line should I stop at during stepping through, place my new file in the directory and then continue debugging so that it picks up the created file?
public void OnDebug()
{
OnStart(null);
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
protected override void OnStart(string[] args)
{
string pathToWatch = ConfigurationManager.AppSettings["DirectoryToWatch"];
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = pathToWatch;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;
watcher.Created += new FileSystemEventHandler(FileCreated);
watcher.EnableRaisingEvents = true;
}
private void FileCreated(object source, FileSystemEventArgs e)
{
try
{
DateTime dt = File.GetCreationTime(e.FullPath);
File.Move(e.FullPath.ToString(), ConfigurationManager.AppSettings["DirectoryToMoveTo"] + e.Name + dt.ToString());
LogEvent($"New file found and moved \n {e.FullPath.ToString()}");
}
catch (IOException ex)
{
LogEvent(ex.ToString());
}
}

You can start by adding a breakpoint inside the function FileCreated.
I suggest you add a breakpoint at
DateTime dt = File.GetCreationTime(e.FullPath);
When you create a new file in the directory being watched, the FileSystemWatcher gets notified and the function FileCreated is called.
I also suggest you to log the destination path for your move. Just to make sure it's a valid path.

Related

how to use a separate STA thread to call clipboard from timer in console application?

I am struggling with using Clipboard from a console application. The error handler would return the following error.
"Current thread must be set to single thread apartment (STA) mode before OLE calls can be made"
I set the STA attribute to the main function and that worked well when calling from main. However, I need to cyclically call that function and in this case I get back that error.
I'm trying to figure out how to use an own thread in my funtion. Now, it just works once but in the 2nd call from my timer, I am not able to reach the area of the code after where I created the thread
public string getRawData()
{
string sChatRawTxt = string.Empty;
try
{
// copy data to clipboard using an Autoit script
Process.Start("copyChatToClipboard.au3");
System.Threading.Thread.Sleep(500);
Thread staThread = new Thread(x =>
{
if (Clipboard.ContainsText())
{
sChatRawTxt = Clipboard.GetText();
Clipboard.Clear();
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return sChatRawTxt;
}
This is the timer from where my function is called. If I set a breakpoint to separateComments, it only works one time, then I am no longer able to reach that position. Do I have to somehow close the thread from before?
public void OnTimedEvent_scannerCyclic(object source, ElapsedEventArgs e)
{
string sRawTxt = getRawData();
// then separate/ remove the useless data
string sComments = SeparateComments(sRawTxt);
}
[STAThread]
public static void Main(string[] args)
{
stdTimer = new System.Timers.Timer(1000);
stdTimer.Elapsed += new ElapsedEventHandler(this.OnTimedEvent_scannerCyclic);
stdTimer.Enabled = true;
while (true)
{
// main program
//System.Threading.Thread.Sleep(1000);
}
}
thanks a lot for help
So the only solution i figured was to use my own timer that i implemented in the main as below
TimeSpan deltaT = TimeSpan.FromMilliseconds(1000);
DateTime timeLastCall = DateTime.Now;
while (true)
{
// main program
DateTime currentTime = DateTime.Now;
if(currentTime - timeLastCall > deltaT)
{
Scanner.mainCyclicCall();
timeLastCall = currentTime;
}
System.Threading.Thread.Sleep(100);
}
I dont have a lot of c# experience, it is actually my first little project. I dont know if there is a better way to cyclically access Clipboard in a console application. Also using a dispatcher timer did not work out, I read console apps dont have a dispather.

Using property files in Web Applications [duplicate]

This question already has answers here:
How to get properties file from /WEB-INF folder in JSF?
(3 answers)
Closed 7 years ago.
I'm developing a web application(this is my first time) and pretty confused about using property files. I don't know where to put the property files.
The problem is that i have put it under the WEB_INF folder. And when i test run it as a Java Application to check whether Database connections are working according to the properties in the property file it is working without any problem.
But when i run it in a Server as a Web Application it fails to load the properties file saying it could not find the file in the path specified. I tried using every possible path i could give and changing the file directories within the whole project. But I kept getting the same error.
Then i changed my class again from scratch thinking there's some kind of a bug withing my code where i load the properties file. And it seems that it could not find the file either when deployed as a Web App. But my test application works fine. Where do i put this file and how do i use it. I have read #BalusC's answer in this thread https://stackoverflow.com/a/2161583/2999358 but i have no idea why this happens. Can someone help me on this?
I'm using Tomcat 8, Eclipse IDE and building on JSF framework.
Class where i load my properties file
public class ConfigCache {
private static final File FILE = new File("./WebContent/WEB-INF/conf/config.properties");
private static final Properties PROPERTIES = new Properties();
public static final String JDBC_DRIVER = ConfigCache.getProperty("db.driverName");
public static final String DATABASE_URL = ConfigCache.getProperty("db.url");
public static final String DATABASE_USERNAME = ConfigCache.getProperty("db.user");
public static final String DATABASE_PASSWORD = ConfigCache.getProperty("db.pass");
public ConfigCache() {
}
public static String getProperty(String key) {
if (PROPERTIES.isEmpty()) {
loadProperties();
}
Object value;
return (value = PROPERTIES.get(key)) == null ? "" : value.toString();
}
private static void loadProperties() {
if (!FILE.exists()) {
throw new IllegalArgumentException("The 'config.properties' has not been found.");
}
try {
FileInputStream fis = null;
try {
fis = new FileInputStream(FILE);
PROPERTIES.load(fis);
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException exp) {
System.out.println("IOException #" + ConfigCache.class + " # loadProperties() : " + exp);
}
}
} catch (Exception exp) {
System.out.println("Exception #" + ConfigCache.class + " # loadProperties() : " + exp);
}
}
}
Folder Structure
Try With this.
put the property in src folder.
Your file is in the WEB-INF directory. This means it's part of the war and reachable as part of the class path. That's perfectly ok, since it makes it portable and independant of the web container installation (e.g. Tomcat).
You can load any file in the class path as a resource:
getClass().getResourceAsStream("/conf/config.properties")
This means you can write your code like this:
private static void loadProperties() {
InputStream is = getClass().getResourceAsStream("/conf/config.properties");
PROPERTIES.load(fis);
}
(Error handling omitted)
You can explode (unzip) your war/ear file and see the contents or folder structure of it and find why your code doesnt work. The reason is that the folder WebContent doesnt exist in your ear/war , but does exist only when run via eclipse. This is the reason why its always better to follow the solution provided in the link posted so that you can retrieve the porperty files from classpath. The below code fetches your property file in eclipse but not in the server.
private static final File FILE = new File("./WebContent/WEB-INF/conf/config.properties");
Contents of WAR file (from JournelDev), it contains WEB-INF directory but there would be no WebContent directory above it

Eclipse API: How to schedule a job that joins with another recently scheduled job?

More specifically, how do I create an IResource and then immediately delete an IResource that was created within the first IResource?
I am creating an IProject, and the Eclipse API automatically creates a ".project" IFile within the IProject. I want to delete the ".project" file that is inside the recently created IProject. Here's is my attempt, to give an idea:
project.create(null);
// Remove the .project file that was created with the IProject.
// Do I need a separate thread here, that waits until the project
// has been created?
IResource file = project.findMember(".project");
file.delete(false, null);
I believe that I am running into a race condition, correct? I think the solution would be to have findMember and delete methods wait until my project has been created (ie I want findMember and delete to "join" with the thread invoked by create). Is this the right approach?
Extra information
If interested, and to provide some context, this question is related to my efforts in the open source project Solstice. Specifically, I am addressing this issue where we are replicating the developer's workspace in real time. I am working on the ResourceSynchronizer that receives messages about changes in the developer's workspace and replicates those changes in the copy workspace. Thus, it receives a message to add an IProject, and then it receives another message to add the corresponding ".project". Since the IProject addition automatically adds the ".project", I am trying to remove the ".project" immediately after adding the IProject. If I try to add an ".project" when it already exists, a warning is generated. Thus, I am trying to avoid this warning.
Thank you.
If you have an existing .project file you can use it to create the project like this:
IWorkspace workspace = ResourcesPlugin.getWorkspace();
// Read the existing project file - this does not have to be in the workspace
IPath path = new Path(existingProjectFile);
IProjectDescription projectDesc = workspace.loadProjectDescription(path);
// Make sure project location is the default in the workspace
projectDesc.setLocation(null);
// Create 'handle' to project
IProject project = workspace.getRoot().getProject(projectName);
// Create the project using the existing description data
project.create(projectDesc, progress monitor);
The project.create should really be done in a WorkspaceModifyOperation.
My solution to the original post is below, which schedules a job to create an IProject, then joins and schedules another job to delete the .project. From what I have learned, this works because when Eclipse creates a new project, it does the following:
It creates the top-level directory for the project,
fires an ADDED event for the project.
It creates a .project file inside the project folder,
fires an ADDED event for the .project file.
// Create "FamilyMember" so each job will be recognized as being in the
// same "family". In this case, use the same "lastName".
private class FamilyMember extends Job
{
private String lastName;
public FamilyMember(String firstName, String lastName)
{
super(firstName + " " + lastName);
this.lastName = lastName;
}
#Override
protected IStatus run(#Nullable IProgressMonitor monitor)
{
// Take care of family business
return Status.OK_STATUS;
}
#Override
public boolean belongsTo(Object family) {
return lastName.equals(family);
}
}
In another method, do the following:
final IProject project = (IProject) resource; // Project to be created.
// Need to create a project that does not have a .project file.
// To do so, create a project, then delete its .project file.
Job createProjectJob = new FamilyMember("Create", "SyncProject")
{
#Override
protected IStatus run(#Nullable IProgressMonitor monitor)
{
try
{
ResourceUtility.createProject(project);
}
catch (CoreException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return Status.OK_STATUS;
}
};
// This job deletes the .project file from the final project defined above.
Job deleteProjectFileJob = new FamilyMember("Delete", "SyncProject")
{
#Override
protected IStatus run(#Nullable IProgressMonitor monitor)
{
try
{
project.findMember(".project").delete(false, null);
}
catch (CoreException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return Status.OK_STATUS;
}
};
// Schedule and join the jobs.
IJobManager manager = Job.getJobManager();
createProjectJob.schedule();
try
{
manager.join("SyncProject", null);
deleteProjectFileJob.schedule();
}
catch (OperationCanceledException | InterruptedException e)
{
SolsticeClient.getLogger().logWarning("Exception during project without .project creation: "
+ e);
}
The following links were also used:
http://www.eclipse.org/articles/Article-Concurrency/jobs-api.html
http://help.eclipse.org/indigo/ntopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/jobs/IJobManager.html

Using multiple FileSystemWatchers

I want to use multiple FileSystemWatchers to watch different text files.
I am successful in creating the watchers and the file change events are being invoked and I can add the changes in the text files to a string and display this on a form.
What I want to know is how I can tell which watcher is causing the event?
Eg. watcher1, watcher2 or watcher3?
I know I can find out the path and file name of the file that has changed but this doesn't really help me.
I realize you already found your own way to do this, but I recommend you look at the sender parameter within the event that is being fired. This is common for a lot of events. Here is a small example:
private static FileSystemWatcher watcherTxt;
private static FileSystemWatcher watcherXml;
static void Main(string[] args)
{
String dir = #"C:\temp\";
watcherTxt = new FileSystemWatcher();
watcherTxt.Path = dir;
watcherTxt.Filter = "*.txt";
watcherTxt.EnableRaisingEvents = true;
watcherTxt.Created += new FileSystemEventHandler(onCreatedFile);
watcherXml = new FileSystemWatcher();
watcherXml.Path = dir;
watcherXml.Filter = "*.xml";
watcherXml.EnableRaisingEvents = true;
watcherXml.Created += new FileSystemEventHandler(onCreatedFile);
Console.ReadLine();
}
private static void onCreatedFile(object sender, FileSystemEventArgs e)
{
if (watcherTxt == sender)
{
Console.WriteLine("Text Watcher Detected: " + e.FullPath);
}
if (watcherXml == sender)
{
Console.WriteLine("XML Watcher Detected: " + e.FullPath);
}
}

File Read/Write Locks

I have an application where I open a log file for writing. At some point in time (while the application is running), I opened the file with Excel 2003, which said the file should be opened as read-only. That's OK with me.
But then my application threw this exception:
System.IO.IOException: The process cannot access the file because another process has locked a portion of the file.
I don't understand how Excel could lock the file (to which my app has write access), and cause my application to fail to write to it!
Why did this happen?
(Note: I didn't observe this behavior with Excel 2007.)
Here is a logger which will take care of sync locks. (You can modify it to fit to your requirements)
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace Owf.Logger
{
public class Logger
{
private static object syncContoller = string.Empty;
private static Logger _logger;
public static Logger Default
{
get
{
if (_logger == null)
_logger = new Logger();
return _logger;
}
}
private Dictionary<Guid, DateTime> _starts = new Dictionary<Guid, DateTime>();
private string _fileName = "Log.txt";
public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}
public Guid LogStart(string mesaage)
{
lock (syncContoller)
{
Guid id = Guid.NewGuid();
_starts.Add(id, DateTime.Now);
LogMessage(string.Format("0.00\tStart: {0}", mesaage));
return id;
}
}
public void LogEnd(Guid id, string mesaage)
{
lock (syncContoller)
{
if (_starts.ContainsKey(id))
{
TimeSpan time = (TimeSpan)(DateTime.Now - _starts[id]);
LogMessage(string.Format("{1}\tEnd: {0}", mesaage, time.TotalMilliseconds.ToString()));
}
else
throw new ApplicationException("Logger.LogEnd: Key doesn't exisits.");
}
}
public void LogMessage(string message)
{
lock (syncContoller)
{
string filePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (!filePath.EndsWith("\\"))
filePath += "\\owf";
else
filePath += "owf";
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
filePath += "\\Log.txt";
lock (syncContoller)
{
using (StreamWriter sw = new StreamWriter(filePath, true))
{
sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.sss") + "\t" + message);
}
}
}
}
}
}
How do you write the log? Have your own open/close or use some thirty party product?
I thing that the log is opened and locked only when it writes something. Once the data writing is finished, the code closes the file and, of course, releases the lock
This seems like a .NET issue. (Well; a Bug if you ask me).
Basically I have replicated the problem by using the following multi-threaded code:
Dim FS As System.IO.FileStream
Dim BR As System.IO.BinaryReader
Dim FileBuffer(-1) As Byte
If System.IO.File.Exists(FileName) Then
Try
FS = New System.IO.FileStream(FileName, System.IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
BR = New System.IO.BinaryReader(FS)
Do While FS.Position < FS.Length
FileBuffer = BR.ReadBytes(&H10000)
If FileBuffer.Length > 0 Then
... do something with the file here...
End If
Loop
BR.Close()
FS.Close()
Catch
ErrorMessage = "Error(" & Err.Number & ") while reading file:" & Err.Description
End Try
Basically, the bug is that trying to READ the file with all different share-modes (READ, WRITE, READ_WRITE) have absolutely no effect on the file locking, no matter what you try; you would always end up in the same result: The is LOCKED and not available for any other user.
Microsoft won't even admit to this problem.
The solution is to use the internal Kernel32 CreateFile APIs to get the proper access done as this would ensure that the OS LISTENs to your request when requesting to read files with a share-locked or locked access.
I believe I'm having the same type of locking issue, reproduced as follows:
User 1 opens Excel2007 file from network (read-write) (WindowsServer, version unkn).
User 2 opens same Excel file (opens as ReadOnly, of course).
User 1 successfully saves file many times
At some point, User 1 is UNABLE to save the file due to message saying "file is locked".
Close down User 2's ReadOnly version...lock is released, and User 1 can now save again.
How could opening the file in ReadOnly mode put a lock on that file?
So, it seems to be either an Excel2007 issue, or a server issue.

Resources