I am trying to develop a proof of concept WCF web service which uses the FileSystemWatcher class to listen to a directory and simply outputs the type of change and the full path of files which are changed.
I have a sample console application which works as expected but when I port this into a WCF library the event handler for file changes never fires.
Code:
public void MonitorFolder()
{
System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher();
watcher.Path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "folder-to-watch");
watcher.IncludeSubdirectories = false;
watcher.Changed += watcher_Changed;
watcher.Filter = "*.*";
watcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName;
watcher.EnableRaisingEvents = true;
}
void watcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
Console.WriteLine(string.Format("Change: {0}, File: {1}", e.ChangeType, e.FullPath));
}
And inside the client class which calls the service:
static void Main(string[] args)
{
FileListenerClient c = new FileListenerClient();
c.MonitorFolder();
c.Close();
}
Any ideas why this does not pick up file changes?
Environment.SpecialFolder.Desktop means desktop of current user.
If your service stars under LocalSystem account (or similar), then it monitors its own desktop, not the desktop of current interactive user, where you're changing files or folders.
Of course, desktop of service account remains unchanged, thus, event doesn't fire.
Maybe you misunderstood the purpose of a WCF service compared to a normal Windows Service. A WCF service is by default only activated on call. It is not something that is running all the time in the background like a normal Windows Service.
For your exact example, you will probably need a kind of waiting before you close and you need your watcher to be just a local variable in your function, but a class variable for it to work.
Assuming a) the behaviour you have detailed is what you want and b) you are watching the correct folder, have you looked at the fairly well known issues with InternalBufferSize and FileSystemWatcher?
Have a read of this http://social.msdn.microsoft.com/Forums/vstudio/en-US/4465cafb-f4ed-434f-89d8-c85ced6ffaa8/filesystemwatcher-reliability
Related
I have a C# Windows Forms application that is referencing a DLL (managed code) that is using SeriLog to log events. The SeriLog logger is defined in the Windows Forms (main) application, so I have control over the type of sink I am using. Currently I am just logging to a local text file.
My question: is there an elegant way for me to view the log in a Listbox or similar WinForms control in real time while the application is running? The only way I can see at the moment is to read the Log file every few seconds and display the latest item. But I am sure there may be a more elegant way to do capture just the last one or two logged items?
This has the exact answer you're looking for: Is it possible to display Serilog log in the program's GUI?
However something has happened in the last 5 years!!! There's now a library called:
https://github.com/serilog/serilog-sinks-reflectinsight
We've added a Serilog Sink for ReflectInsight live log viewer. This allows you to leverage your current investment in Serilog, but leverage the power and flexibility that comes with the ReflectInsight viewer. You can view your Serilog messages in real-time, in a rich viewer that allows you to filter out and search for what really matters to you.
Given that you have control over the logging pipeline and can choose the sink(s) that will be used, one option would be to use the Serilog.Sinks.RichTextBox sink which can write logs to a RichTextBox control with colors, formatting, etc.
The sink was originally built for WPF apps, but you can easily use it in a Windows Forms application with an ElementHost. There's an example in the repository that shows how to use it with Windows Forms.
Disclaimer: I'm the author of the Serilog.Sinks.RichTextBox sink.
Use FileSystemWatcher to monitor the file change and then update that Listbox in the OnChanged event handler
static void Main()
{
using var watcher = new FileSystemWatcher(#"C:\path\to\folder");
//choose what you wish
watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Security
| NotifyFilters.Size;
watcher.Changed += OnChanged;
watcher.Created += OnCreated;
watcher.Deleted += OnDeleted;
watcher.Renamed += OnRenamed;
watcher.Error += OnError;
watcher.Filter = "YourLogFile.txt";
watcher.IncludeSubdirectories = false;
watcher.EnableRaisingEvents = true;
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
private static void OnChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
//Console.WriteLine($"Changed: {e.FullPath}");
//Update your Listbox content
}
I'm working on a custom server based on HttpListener. It's working fairly well, until I try to use a FileSystemWatcher to make it able to respond to changing script content without needing to reboot the server. It doesn't appear to ever fire.
The relevant code looks like this:
foreach (var script in Directory.EnumerateFiles(folder, mask))
{
var filename = Path.GetFileNameWithoutExtension(script);
var compileResult = scriptCompiler.CompileScript(script);
if (compileResult.Errors.Count > 0)
throw new Exception(compileResult.Errors.ToString());
AddScriptType(compileResult.GeneratedAssembly.GetType(filename));
}
this._watcher = new FileSystemWatcher(folder, mask);
_watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
var changed = (s, e) => RebuildScript(scriptCompiler, e);
_watcher.Changed += changed;
_watcher.Created += changed;
_watcher.Deleted += this.ScriptDeleted;
_watcher.EnableRaisingEvents = true;
This seems pretty straightforward, but RebuildScript never gets called if I go in and change one of the script files.
I can't help but wonder if HttpListener is interfering with some messaging architecture needed to make this work properly. The server runs on the main thread, in an infinite loop of waiting for an HTTP request, processing it, and returning the response. Could that be causing FileSystemWatcher to never receive events from the OS? If not, how do I figure out what's causing this to fail?
As #HansPassant mentioned in the comments, the options set for NotifyFilter prevent the event from firing.
According to https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.notifyfilter(v=vs.110).aspx
, "[t]he default is the bitwise OR combination of LastWrite, FileName, and DirectoryName."
This post discusses choosing the appropriate FileSystemWatcher filters to achieve your goals.
Which filter of FileSystemWatcher do I need to use for finding new files. As #DavidBrabant mentioned in an answer in this post, I would suggest setting _watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;
I have to create a program that monitors changes in file size. I already made a simple windows service and filesystemwatcher so I am now familiar w/ the concept. I also made a code that checks for the filesize (made it in a form button)but haven't yet implemented in my filesystemwatcher. How do I create a windows service that has a filewatcher that monitors the file size? Do I have to put a filesystemwatcher inside the windows service and call the watcher via the OnStart method?
If you're making a Window's service, then you'll want to do it programmatically. I usually keep forms out of my services and make a separate interface for them to communicate. Now the FileSystemWatcher doesn't have an event to watch solely for size, so you'll want to make a method that ties to FileSystemWatcher.Changed to check for modifications to existing files. Declare and initialize the control in your OnStart method and tie together the events as well. Do any cleanup code in your OnStop method. It should look something like this:
protected override void OnStart(string[] args)
{
FileSystemWatcher Watcher = new FileSystemWatcher("PATH HERE");
Watcher.EnableRaisingEvents = true;
Watcher.Changed += new FileSystemEventHandler(Watcher_Changed);
}
// This event is raised when a file is changed
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
// your code here
}
Also note, the FileSystemWatcher will fire off multiple events for a single file, so when you're debugging watch for patterns to work around it.
You can simply enable your filesystemwatcher object in the OnStart method by setting
EnableRaisingEvents = true;
Then handle the event. That should do it.
you can create a delegate to handle what has changed like
myWatcher.Changed += new FileSystemHandler(FSWatcherTest_Changed);
private void FSWatcherTest_Changed(object sender,
System.IO.FileSystemEventArgs e)
{
//code here for newly changed file or directory
}
And so on
I would recommend you to read this article http://www.codeproject.com/Articles/18521/How-to-implement-a-simple-filewatcher-Windows-serv
Also have this delegate on_start in windows service
I'm using a FileSystemWatcher on my C# application (running on Windows) in order to update in my app the files that I'm currently browsing.
It's work well when I browse a local directory. I am notified when a file is renamed, deleted or added.
But for example when I rename a file on the network drive the first time, the FileSystemWatcher notifies me of a rename action and then, when I rename the same file or another file, the FileSystemWatcher notifies me of an error :
the specified server cannot perform the requested operation.
Then the FileSystemWatcher not notify me about anything.
Sometimes I can rename twice before the FileSystemWatcher not notify me nothing...
Here is my test code :
static void Main(string[] args)
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"N:\prive\defFolder";
watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
watcher.Created += new FileSystemEventHandler(watcher_Changed);
watcher.Deleted += new FileSystemEventHandler(watcher_Changed);
watcher.Renamed += new RenamedEventHandler(watcher_Renamed);
watcher.Error += new ErrorEventHandler(watcher_Error);
watcher.EnableRaisingEvents = true;
Console.Read();
watcher.Dispose();
}
static void watcher_Error(object sender, ErrorEventArgs e)
{
Console.WriteLine("error : " + e.GetException().Message);
}
static void watcher_Renamed(object sender, RenamedEventArgs e)
{
Console.WriteLine("rename success");
}
static void watcher_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine("change success");
}
First of all, file system monitoring of remote shares is always going to be somewhat unreliable. You should not depend on your app getting all the events - in fact, I would suggest you provide a backup polling mechanism to check for changes that you may have missed. A refresh button in the GUI could be another option, depending on your app.
That said, your particular problem doesn't seem to be that uncommon. I googled around a bit and found these things:
Problem with FileSystemWatcher on 2003 server box - seems to be the same problem as you have, with a samba share and that "The specified server cannot perform the requested operation" error message.
SO Question regarding the same issue and one of the answers indicate that it worked for some customers and not for others
My guess is that this is a problem with certain versions (or configuration) of Samba combined with Windows. Are there anything in the Samba logs on the linux server that could point you towards the cause of the problem?
As an immediate workaround, I suggest you try these things:
Add a polling mechanism that ensures that you do get the folder changes even if the FSW breaks down
When the FSW breaks, try to "restart" it by creating a new one. You may also want to check if EnableRaisingEvents is set to false when you get the error - maybe you can just set it to true to start receiving events again.
(Grasping for straws here) try playing around with the internal buffer size in case that's the problem (I doubt it, but it's worth a shot)
if (Directory.Exists(monitorPath))
{
watcher.Path = monitorPath;
watcher.IncludeSubdirectories = true;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime;
watcher.InternalBufferSize = 65536;
watcher.Filter = "test_prod-Pg1_ICT*";
watcher.Changed += new FileSystemEventHandler(fileChangedEvent);
watcher.EnableRaisingEvents = true;
LogEvent("Folder Syncronization Service is Started!");
}
I created a Window Service FileSystemWatcher based class to Monitor a Samba Shared Folder onChanges and used DifferenceEngine from CodeProject to check the different and copy over to Window Shared Folder Path if there is a changes. I also added a Timer to check every 10 seconds to handle when network is fail. There is a List Array To store the changes count. Added into List when File Changed event is Raised and remove the List when is success.
I have tested two HP Laptop on Window 7 Pro OS, working fine.
But Failed to working on other Window 7 Pro Laptop and also Window XP Pro SP3 Desktop. (We are on same Company Network/VLAN and Service Pack)
The failed is mean if i amended something in Samba Shared Folder, it will not Sync the Latest content to Window Share Path.
I also has added these
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
[PermissionSetAttribute(SecurityAction.InheritanceDemand, Name = "FullTrust")]
in the top of the coding, it seem does not work
For people recently having this kind of problem, quoting from my answer to this question:
We are yet to test that this is a suitable alternative in our
situation, but it seems that Microsoft introduced
PhysicalFileProvider some time ago.
It has a UsePollingFileWatcher property specifically for this
kind of problem.
Then for the file watching, it seems you want the Watch method.
The documentation is currently showing it as not available on certain
platforms or target frameworks, but in practice the NuGet package
claims to be .NET Standard 2.0 compatible, so that should cover
basically everything.
I'm building a C# application that will monitor a specified directory for changes and additions and storing the information in a database.
I would like to avoid checking each individual file for modifications, but I'm not sure if I can completely trust the file access time.
What would be the best method to use for getting recently modified files in a directory?
It would check for modifications only when the user asks it to, it will not be a constantly running service.
Use the FileSystemWatcher object. Here is some code to do what you are looking for.
// Declares the FileSystemWatcher object
FileSystemWatcher watcher = new FileSystemWatcher();
// We have to specify the path which has to monitor
watcher.Path = #"\\somefilepath";
// This property specifies which are the events to be monitored
watcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite | NotifyFilters.FileName | notifyFilters.DirectoryName;
watcher.Filter = "*.*"; // Only watch text files.
// Add event handlers for specific change events...
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
}
I think what you want is provided by the FileSystemWatcher class.
This tutorial describes how to use it to monitor a directory for changes in a simple windows service; How to implement a simple filewatcher Windows service in C#
Hmm... interesting question. Initially I'd point you at the FileSystemWatcher class. If you are going to have it work, however, on user request, then it would seem you might need to store off the directory info initially and then compare each time the user requests. I'd probably go with a FileSystemWatcher and just store off your results anyhow.
If you only need it to check when the user asks rather then all the time, don't use the FileSystemWatcher. Especially if it's a shared resource - the last thing you want is 50 client machines watching the same shared directory.
It's probably just a typo, but you shouldn't be looking at the file access time, you want to look at the file modification time to pick up changes. Even that's not reliable.
What I would do is implement some sort of checksum function on the file date and byte size, or other file system properties. That way I wouldn't be looking for changes in the complete file - only the properties of it and I can do it on request, rather than trying to hold a connection to a remote resource to monitor it.
A heavier solution would be to do it the other way around, and install a service on the machine hosting the shared drive which could monitor the files and make note of the changes. Then you could query the service rather than touching the files at all - but it's probably overkill.