I am working on a windows service which will look for backup files in a particular folder. When it finds one the service will move all the backup files from that location and move them to an archived folder.
I have used FileSystemWatcher before but since it doesn't work on Servers I am using DirectoryInfo to look for the files.
The requirement is to run this service at every 5 minutes interval to look for any new backup files coming in.
I am stuck with the timer implementation.
Following is my code:
I want to call MoveToProcessed(processed) method from the ElapsedEventHandler. but I am getting error CS0149 - Method name expected.
protected override void OnStart(string[] args)
{
DirectoryInfo dir = new DirectoryInfo(backupdirectory);
// Other unrelated code omitted
// Move all the Backup files to Processed folder at certain intervals.
createOrderTimer = new System.Timers.Timer();
//***** ERROR ON THE FOLLOWING LINE *****
createOrderTimer.Elapsed += new ElapsedEventHandler(MoveToProcessed(processed));
//***************************************
createOrderTimer.Interval = 300000; // 15 min
createOrderTimer.Enabled = true;
createOrderTimer.AutoReset = true;
createOrderTimer.Start();
}
private void MoveToProcessed(string processed)
{
// Code here backs up and restores files
}
You can easily call a method from an event handler, but the event handler method itself must match a specific signature. For the System.Timers class, it should look something like this:
private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
So you can simply create a method with this signature, assign it as an event handler, and then call your method from there:
// Elapsed event handler calls our other method
private static void CreateOrderTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Not sure what the string argument represents, or how it should be set
MoveToProcessed("some string");
}
// We can assign the event handler above when creating the Timer:
protected override void OnStart(string[] args)
{
var createOrderTimer = new System.Timers.Timer
{
Interval = TimeSpan.FromMinutes(15).TotalMilliseconds,
AutoReset = true
};
createOrderTimer.Elapsed += CreateOrderTimer_Elapsed;
createOrderTimer.Start();
}
Related
I have developed a windows service for copying a file from one location to another.
Since I need to run the service in the background there is a necessity of implementing a timer function.
Service.cs
protected override void OnStart(string[] args)
{
//OnStart(new string[0]);
}
public void Start()
{
timer1 = new Timer();
this.timer1.Interval = 30000; //every 30 seconds
41 ***this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.mysql);***
timer1.Enabled = true;
43 mysql();
}
static void mysql()
{
**File copy code included in this function.
}
The error triggers in line 41 mentioned above and is,
No overload for 'mysql' matches delegate 'ElapsedEventHandler'.
set param on mysql() like this
static void mysql(object sender, ElapsedEventArgs e)
I hope it works for you :)
++ added via comment
this code will allows timer work with interval
add this code in Start()
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.mysql_tick);
and add this code out of Start()
private void mysql_tick( object sender, EventArgs e ){
blah blah... }
++ after that you need to use timer1.Start(); for work with mysql_tick
++ timer1.Stop(); will halt work.
I have this code behind in asp.net page:
protected void LoadFile(object sender, EventArgs e)
{
try
{
Timer myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler( RemoveFile );
myTimer.Interval = 60000;
myTimer.Start();
}
catch (Exception)
{
}
}
private void RemoveFile(object source, ElapsedEventArgs e)
{
string path = UniquePath();
File.Delete(path);
}
When LoadFile event handler fired the RemoveFile function fired after 60 sec(as defined in this row myTimer.Interval = 60000), if LoadFile fired again after 40 seconds the RemoveFile will fire in 20 seconds.
My question is how to make the RemoveFile function to be activated after 60 seconds from last call of the LoadFile event hanlder?
May be you could use
myTimer.Stop(); just after Timer myTimer = new Timer();
I would use Microsoft's Reactive Extensions (NuGet "Rx-Main") for this. The code becomes:
private SerialDisposable _serialDisposable = new SerialDisposable();
protected void LoadFile(object sender, EventArgs e)
{
_serialDisposable.Disposable =
Observable
.Interval(TimeSpan.FromSeconds(60.0))
.Subscribe(n =>
{
string path = UniquePath();
File.Delete(path)
});
}
Now, observables are like events and calling .Subscribe is like attaching to an event. The .Subscribe call returns an IDisposable which you can use to detach from the observable by calling .Dispose(). The SerialDisposable object is a special disposable class provided by Rx that lets you assign new disposables and automatically dispose any previously assigned disposables. This automatically resets the timer every time LoadFile is run.
This is just one use of Rx - it has so many more uses and is very powerful and worth learning.
I am trying to use FileSystemWatcher to read a textfile as soon as anything gets updated into textfile in Windows Service.Now the problem that i am facing is not getting the way where i should put my FileSystemWatcher code so that i would get called as soon as textfile gets changed.Do i need to add this into OnStart() Method of Windows Service or anywhere else.
Here is my Code Structure..
protected override void OnStart(string[] args)
{
_thread = new Thread(startReadingTextFile);
_thread.Start();
}
public void startReadingTextFile() {
_freader = new AddedContentReader(TextFileLocation);
}
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
string addedContent = _freader.GetAddedLines();
}
Please help me .Thanks ..
Updated Code..
protected override void OnStart(string[] args)
{
if (lastLineReadOffset == 0)
{
_freader = new AddedContentReader(TextFileLocation);
}
//If you have saved the last position when the application did exit then you can use that value here to start from that location like the following
//_freader = new AddedContentReader("E:\\tmp\\test.txt",lastReadPosition);
else
{
_freader = new AddedContentReader(TextFileLocation, lastLineReadOffset);
}
FileSystemWatcher Watcher = new FileSystemWatcher("C:\\temp");
Watcher.EnableRaisingEvents = true;
Watcher.Changed += new FileSystemEventHandler(Watcher_Changed);
}
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
string addedContent = _freader.GetAddedLines();
//you can do whatever you want with the lines
using (StringReader reader = new StringReader(addedContent))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Call the Processing Function
}
}
}
Do i need to add this into OnStart()
Yes.
But, there is no need to create a thread for this purpose. Once FileSystemWatcher.EnableRaisingEvents is set, then events will be fired in the thread pool: you can return from OnStart.
Richard's answer is correct. However, the Changed event fires at least twice because by default FileSystemWatcher fires it once when the file is created and then again every time the file system flushes its contents to the disk. For large files you may get multiple Change events caused by multiple disk writes. If you try to open the file the first time Change fires you may get errors if the file is locked by the writing process or get an incomplete file content.
The most reliable way I have discovered is to set a timer with a short interval (a few seconds) on the very first Change event for a new file and then reset it every subsequent time the event fires for the same file. You then open the file in the timer's own Elapsed event when it does fire a few seconds after the last Change event was fired for the file.
This requires some extra code and variables:
First, create a Dictionary<string, Timer> to keep track of timers per filename.
Inside your Change event handler you need to check if the dictionary already contains the file's name as a key (inside a lock block to take care of thread concurrency issues).
If it isn't then:
create a new Timer instance
set its state object to the name of the file so when its Elapsed event fires you'll know which file you are supposed to process (the same end result can also be achieved using a closure and a lambda function but a state object is simpler)
add the new timer instance to the dictionary using the file name as the key
If it is (i.e. this is not the first Change event for that file):
look up the Timer instance in the dictionary
reset its interval to push its Elapsed event further
Then in the handler of the timer's Elapsed event you do your actual processing and cleanup:
get the file name from the timer's state object passed in the event arguments
look up the Timer instance in the dictionary by the file name and dispose of it
remove the timer from the dictionary, i.e. Remove(key) where key is the file name (the three actions above should happen inside a lock block)
open the file and do whatever you need with it.
Here's how you might want to implement this logic inside your service:
const int DELAY = 2000; // milliseconds
const WatcherChangeTypes FILE_EVENTS = WatcherChangeTypes.Created | WatcherChangeTypes.Changed | WatcherChangeTypes.Renamed;
FileSystemWatcher _fsw;
Dictionary<string, Timer> _timers = new Dictionary<string, Timer>();
object _lock = new object();
public void Start()
{
_fsw = new FileSystemWatcher(Directory, FileFilter)
{
IncludeSubdirectories = false,
EnableRaisingEvents = true
};
_fsw.Created += OnFileChanged;
_fsw.Changed += OnFileChanged;
}
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
try
{
// When a file is created in the monitored directory, set a timer to process it after a short
// delay and add the timer to the queue.
if (FILE_EVENTS.HasFlag(e.ChangeType))
{
lock (_lock)
{
// File events may fire multiple times as the file is being written to the disk and/or renamed,
// therefore the first time we create a new timer and then reset it on subsequent events so that
// the file is processed shortly after the last event fires.
if (_timers.TryGetValue(e.FullPath, out Timer timer))
{
timer.Change(DELAY, 0);
}
else
{
_timers.Add(e.FullPath, new Timer(OnTimerElapsed, e.FullPath, DELAY, 0));
}
}
}
}
catch (Exception ex)
{
// handle errors
}
}
private void OnTimerElapsed(object state)
{
var fileName = (string)state;
lock (_lock)
{
try { _timers[fileName].Dispose(); } catch { }
try { _timers.Remove(fileName); } catch { }
}
// open the file ...
}
I'm fooling around with the FileSystemWatcher in 4.0. I find this very useful but am getting caught in a loop. I'm trying to monitor whenever an ini is changed and change it back to the correct default (long story) however the change event copying over the new file is causing it to drop into a loop ... Any Ideas > ? I played around with the idea of deleting and recreating thefile to avoid triggering the changed event but this leads to another set of issues with the program that I'd rather avoid. Also I'd imagine I could overwrite the text but this also poses the same issue. Thanks in advance for the help
static void Main() { Watch (#"\\NoFault2010\Lexis\Data\Setup\", "tmconfig.ini", true); }
static void Watch (string path, string filter, bool includeSubDirs)
{
using (var watcher = new FileSystemWatcher (path, filter))
{
watcher.Changed += FileChanged;
watcher.EnableRaisingEvents = true;
Console.WriteLine("Do Not Close ... \n\nThis is a Temporary Configuration Manager for Time Matters ... \n\n\nI'm Listening ............");
Console.ReadLine();
}
}
static void FileChanged (object o, FileSystemEventArgs e)
{
string _right_stuff = #"\\NOFAULT2010\Lexis\Data\Templates\Programs\tmconfig.ini";
string _working = #"\\NOFAULT2010\Lexis\Data\Setup\tmconfig.ini";
System.Threading.Thread.Sleep(2000);
File.Copy(_right_stuff, _working, true);
Console.WriteLine("File {0} has been {1}", e.FullPath, e.ChangeType);
MAIL_IT("SQLMail#lcjlawfirm.com", "TM Master.INI has been altered", "Check the Master INI and Yell At Ecopy Guy " + e.ChangeType + e.FullPath);
}
How would I unsubscribe from the event to avoid entering into this loop.
To temporarily disable the event while you're fiddling with the file yourself:
static void FileChanged (object o, FileSystemEventArgs e)
{
watcher.Changed -= FileChanged;
... correct the file here...
watcher.Changed += FileChanged;
}
Alternatively, you can use a guard variable to detect reentrant calls:
static bool reentrant = false;
static void FileChanged (object o, FileSystemEventArgs e)
{
if (reentrant)
return;
reentrant = true;
... correct the file here...
reentrant = false;
}
Note that you will also want to do exception handling within the method or your file watcher may become permanently disabled if a problem occurs.
I've written an application that depends on filesystemwatcher - and also, sometimes the fsw handler makes a change to a file.
I approached it in two ways - the first was to take the view that my code would be very quick in changing the file - so I did
fsw.EnableRaisingEvents = false;
//make my change
fsw.EnableRaisingEvents = true;
However, if you feel that other files might get changed during that time, you could log the time that you make the change and store that data somewhere...
say, Dictionary mapFileNameTimeChanged ...here you could store the file name...so in your handler you could do something like....
fsw_Changed(object sender, FileSystemEventArgs e)
{
lock (m_mapFileNameChanged)
{
if (m_mapFileNameChanged.ContainsKey(e.FullPath))
{
FileInfo fileInfo = new FileInfo(e.FullPath);
if (fileInfo.LastAccessTime == m_mapFileNameChanged[e.FullPath]
{
return;//not been changed since you last did something with it....
}
}
else
{
m_mapFileNameChanged.Remove(e.FullPath);//discard this now..it has changed since you last looked at it...need to look at it again!
}
}
//do things in your event handler...
lock (m_mapFileNameChanged)
{
// copy or change the file here...
FileInfo fileInfo = new FileInfo(e.FullPath);
m_mapFileNameChanged[strFullPathToFile] = fileInfo.LastAccessTime;
}
}
You could add a boolean (again at the class level) that you could use to track whether the changes were caused by you, and if so, just immediately exit your FileChanged method, ie:
static bool inEdit;
static void FileChanged (object o, FileSystemEventArgs e)
{
if (inEdit)
return;
inEdit = true;
// Do processing
inEdit = false;
}
Unsubscribe is easy, so I wonder if that was the question:
watcher.Changed -= FileChanged
Also, I would create some object to be SynchronizationObject for watcher. There is a problem that by default watcher raises events in new thread, and thus if you unsubscribe after new thread is created, you might run into the problems.
Also of note that FileSystemWatcher may raises multiple events for something you consider as single event, and it might influence functioning of your program.
If you make the watcher a class variable instead of a local variable, then your FileChanged method should be able to access it. Then you should be able to do something like
static void FileChanged (object o, FileSystemEventArgs e)
{
watcher.EnableRaisingEvents = false;
// Edit the file here
watcher.EnableRaisingEvents = true;
}
This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...