File System Watcher Process called from another class not firing events c# - c#

I have a windows service that basically monitors a folder, copies files to a local directory processes the files. The service starts up fine enough calls the Watcher Class and does all of the configuration like it should. So my code works for the setup. However I get 0 events firing. I am wondering if when my StartFolderWatcher() method goes out of scope that my object - even though declared at the class level is somehow getting disposed.
So do I need to run the object continuously in a separate thread ? If so can I get an example of how I should do that Task.Run(()=> myObject)
Relevant Code is below - if more is needed just ask and I will post it.
static class Program
{
static void Main(string[] args)
{
JobProcessor service = new JobProcessor();
if (Environment.UserInteractive)
{
service.RunAsConsole(args);
}
}
private static bool IsDebugMode(string[] args)
{
if (args == null) return false;
if (args[0].ToLower() == "/debug") return true;
return false;
}
}
public partial class JobProcessor : ServiceBase
{
string[] folders = new string[] {"InBoxFolder"};
HotFolderWatch HFW = new HotFolderWatch();
public JobProcessor()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StartFolderWatcher();
}
public void StartFolderWatcher()
{
FileWatcherInfo[] ServiceWatchers = new FileWatcherInfo[4];
ServiceConfiguration sc = new ServiceConfiguration();
for (int i = 0; i < folders.Length; i++)
{
ServiceWatchers[i] = sc.GetWatchFolderSettings(folders[i]);
}
HFW = new HotFolderWatch(ServiceWatchers[0]);
HFW.ReadyToProcess += ReadyToProcess;
HFW.InBoxFolderDisconnected += OnInBoxFolderDisconnected;
HFW.LocalFolderDisconnected += OnLocalFolderDisconnected;
HFW.ProcessFolderDisconnected += OnProcessFolderDisconnected;
}
public void RunAsConsole(string[] args)
{
OnStart(args);
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
OnStop();
}
}
public HotFolderWatch(FileWatcherInfo inbox)
{
this.InboxCacheTimeMilliseconds = inbox.CacheTimeMilliseconds;
this.InBoxFolder = inbox.Folder.Trim();
this.InboxFileFilter = inbox.Filter.Trim();
SetInboxWatcher();
}
private void SetInboxWatcher()
{
InBoxWatcher = new FileSystemWatcher(InBoxFolder, InboxFileFilter);
InBoxWatcher.IncludeSubdirectories = false;
InBoxWatcher.NotifyFilter =
NotifyFilters.LastAccess | NotifyFilters.LastWrite;
InboxCache = MemoryCache.Default;
InboxCachePolicy = new CacheItemPolicy()
{
RemovedCallback = OnRemovedFromInBoxCache
};
InBoxWatcher.Created += new FileSystemEventHandler(OnInBoxChanged);
InBoxWatcher.EnableRaisingEvents = true;
}
private void OnInBoxChanged(object source, FileSystemEventArgs e)
{
InboxCachePolicy.AbsoluteExpiration =
DateTimeOffset.Now.AddMilliseconds(InboxCacheTimeMilliseconds);
InboxCache.AddOrGetExisting(e.Name, e, InboxCachePolicy);
}
}
If in my HotFolderWatch Class I create a FileSystemWatcher in a method as below the code works!
private void CreateWatcher()
{
FileSystemWatcher fsw = new FileSystemWatcher(#"C:\Tests\JobQueue\InFolder","*.txt");
fsw.Created += Fsw_Created;
fsw.EnableRaisingEvents = true;
}
private void Fsw_Created(object sender, FileSystemEventArgs e)
{
string ex = e.FullPath;
WatcherChangeTypes ctmp = e.ChangeType;
// throw new NotImplementedException();
}

Turns out the default constructor of FileSystemWatcher uses the filter FileName by default and I was thinking I would get a last Write or Last Access with out concerning myself with the Name.
I received good information from here :
https://www.codeproject.com/Articles/1220094/NotifyFilters-Enumeration-Explained-FileSystemWatc
The article posted in the link is what helped me to solve my issue.
I had to Ste the NotifyFilters.FileName as one of the filters.

Related

Timer and Processing Issues in C#

I have a service that processes files. Sometimes they process very quickly and sometimes they take a very long time. I can't control the process that sends the files to me. The are randomly dropped on me throughout the day and night. When I use the timer, it seems like the "ProcessFiles" method is abandoned whereever it is when the time has elapsed and ProcessFiles is called again. Since the files contain sensitive information, they can't sit on the server for a long time so I can't set the timer for any longer than 5 minutes and, still, at 5 minutes, the process sometimes interrupts itself. As a result, I have partially processed files. I would appreciate any thoughts and input on this quandary.
System.Timers.Timer _timer;
// As the files come in, massage them and encrypt them
public const string InPath = #"c:\input";
public const string OutPath = #"\c:\output";
public FileMassaging()
{
InitializeComponent();
}
public EventLog MyEventLog = new EventLog();
public string sSource = "FileMassaging";
public string sLog = "FileMassaging";
protected override void OnStart(string[] args)
{
// Create the source, if it does not already exist.
if (!EventLog.SourceExists(sSource))
EventLog.CreateEventSource(sSource, sLog);
// set up the service
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
// set up the service
_timer = new System.Timers.Timer();
_timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
_timer.Interval = 5000;
_timer.Start();
// Update the service state to Running.
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
ProcessFiles();
}
public void ProcessFiles()
{
string[] originalFiles = Directory.GetFiles(InPath + #"\", "*.txt");
foreach (string fileName in originalFiles)
{
// Check and process the file
CheckFile(InPath, OutPath, fileName);
}
}
public void CheckFile(string InPath,Outpath, fileName)
{
// for example only -- actual file processing is much longer
//
string infile = InPath+fileName;
string outfile= OutPath+fileName;
File.Move(infile,outfile,true);
}
For testing and extensiblity I would recommend a different overall structure.
First let's seperate out this work into classes where it makes sense. Lets start with a class called FolderWatcher:
public class FolderWatcher
{
private readonly string _inPath;
private readonly string _outPath;
public bool CurrentlyRunning { get; set; }
public FolderWatcher(string inPath, string outPath)
{
_inPath = inPath;
_outPath = outPath;
}
public void TryProcessFiles(object sender, ElapsedEventArgs e)
{
try
{
this.CurrentlyRunning = true;
ProcessFiles(sender, e);
}
catch (Exception)
{
throw;
}
finally
{
this.CurrentlyRunning = false;
}
}
public void ProcessFiles(object sender, ElapsedEventArgs e)
{
string[] originalFiles = GetFilesInDirectory();
foreach (var originalFile in originalFiles)
{
CheckFile(originalFile);
}
}
// Internal/Virtual so that this can mocked in unit testing.
internal virtual string[] GetFilesInDirectory()
{
return Directory.GetFiles(_inPath + #"\", "*.txt");
}
// Internal/Virtual so that this can mocked in unit testing.
internal virtual void CheckFile(string fileName)
{
string infile = $"{_inPath}{fileName}";
string outfile = $"{_outPath}{fileName}";
File.Move(infile, outfile);
}
}
This class has a single responsibility, to move files in response to an event.
Next let's build a class to wrap the FolderWatcher class that handles the timer functionality:
public class TimedFolderWatcher
{
private readonly FolderWatcher _folderWatcher;
private readonly Timer _timer;
public TimedFolderWatcher(FolderWatcher folderWatcher)
{
_folderWatcher = folderWatcher;
InitTimer();
}
private void InitTimer()
{
_timer.Elapsed += new System.Timers.ElapsedEventHandler(this.ProcessFiles);
_timer.Interval = 5000;
_timer.Start();
}
private void ProcessFiles(object sender, ElapsedEventArgs e)
{
_folderWatcher.TryProcessFiles(sender, e);
}
}
This class also has a single responsibility to call the ProcessFiles method every 5000 milliseconds.
Lastly we can init and call these classes this way:
var fileMassageService = new TimedFolderWatcher(new FolderWatcher(#"c:\input", #"c:\output"));
This approach lends itself to testing and follows the best practices of Dependency Injection which will allow you to use an IOC framework in the future if you need to.
From the MSDN Page on Timers try this (https://msdn.microsoft.com/en-us/library/system.timers.timer.interval(v=vs.110).aspx)
_timer = new System.Timers.Timer(5);
_timer.Elapsed += OnTimer;
_timer.AutoReset = true;
// _timer.Start();
_timer.Enable = true;
private static void OnTimer(object sender, System.Timers.ElapsedEventArgs args) { ProcessFiles(); }

FileWatcher typicall implementation?

I am building an app, where I will watching the files. I am pretty fresh in programming so I (maybe) have little issue, because I dont have some real practice. My program its working, but I dont know how is usally implemented in "real" software. Please overview and comment. Because I like to have much as is possible in DateFiles class and less is possible in MainViewModel.
Yes app in build on MVVM base.
My Current state:
In my MainViewModel
public static string ConfigurationFilesSourcePath2;
private void InitializeFiles()
{
// New instance of DateFiles
DF = new DataFiles();
// Path to DateFiles
DF.ConfigurationFilesSourcePath = ConfigurationFilesSourcePath;
// Run Initialization method to establish "filewatching"
DF.InitializeFiles();
// Refresh ListView in View
RefreshFileList();
// Assign a Handler to PropertyChanged event
DF.PropertyChanged += DF_PropertyChanged;
}
// If something change inside DateFiles
private void DF_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
RefreshFileList();
}
// Refresh file list
public void RefreshFileList()
{
fileslist = new ObservableCollection<Files>();
foreach (var item in DF.fileslist)
{
fileslist.Add(item);
}
NotifyPropertyChanged("fileslist");
}
DataFiles class:
public class DataFiles : ViewModelBase
{
public FileSystemWatcher filewatcher;
public string ConfigurationFilesSourcePath;
public ObservableCollection<Files> fileslist { get; set; } = new ObservableCollection<Files>();
public void InitializeFiles()
{
// Create a new FileSystemWatcher
filewatcher = new FileSystemWatcher();
// Set filter to only catch XAL files
filewatcher.Filter = "*.txt";
// Set the path
filewatcher.Path = ConfigurationFilesSourcePath;
// Subscribe to the Created event
filewatcher.Created += new FileSystemEventHandler(FileOnchanged);
filewatcher.Changed += new FileSystemEventHandler(FileOnchanged);
filewatcher.Deleted += new FileSystemEventHandler(FileOnchanged);
filewatcher.Renamed += new RenamedEventHandler(FileOnRenamed);
// Enable the FileSystemWatcher events
filewatcher.EnableRaisingEvents = true;
RefreshFilesList();
}
private void FileOnchanged(object sender, FileSystemEventArgs e)
{
RefreshFilesList();
}
private void FileOnRenamed(object sender, RenamedEventArgs e)
{
RefreshFilesList();
}
public void RefreshFilesList()
{
fileslist.Clear();
DirectoryInfo dir = new DirectoryInfo(ConfigurationFilesSourcePath);
string[] extensions = new[] { ".txt" };
int nof = 0;
foreach (FileInfo file in dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray())
{
nof++;
fileslist.Add(new Files()
{
FileId = nof,
FileName = file.Name,
FileChanged = file.LastWriteTime.ToString(),
FileCreated = file.CreationTime.ToString(),
OnlyNameWithoutExtension = Path.GetFileNameWithoutExtension(file.Name)
});
NotifyPropertyChanged("fileslist");
}
}
There are several issues with your code. Among most important ones - you rebuild whole file list on every change (while FileSystemEventArgs arguments provide you with info about what has really changed and where) and you don't update your ObservableCollection on UI thread. Look at the following code (but keep in mind that is just a sample for you to spot some problems):
public class DataFiles : IDisposable {
public FileSystemWatcher filewatcher;
private readonly object fileListLock = new object();
// you don't need public setter on this
public ObservableCollection<Files> Fileslist { get; } = new ObservableCollection<Files>();
// pass path here, no need to use property
public void InitializeFiles(string path) {
// dispose existing watcher, if any
DisposeWatcher();
// Create a new FileSystemWatcher
filewatcher = new FileSystemWatcher();
// Set filter to only catch XAL files
filewatcher.Filter = "*.txt";
// Set the path
filewatcher.Path = path;
// Subscribe to the Created event
filewatcher.Created += new FileSystemEventHandler(FileOnchanged);
filewatcher.Changed += new FileSystemEventHandler(FileOnchanged);
filewatcher.Deleted += new FileSystemEventHandler(FileOnchanged);
filewatcher.Renamed += new RenamedEventHandler(FileOnRenamed);
// don't RefreshFilesList on UI thread, that might take some time and will block UI
Task.Run(() => RefreshFilesList());
// Enable the FileSystemWatcher events
filewatcher.EnableRaisingEvents = true;
}
private void FileOnchanged(object sender, FileSystemEventArgs e) {
// lock here to avoid race conditions with RefreshFilesList
lock (fileListLock) {
// better use dictionary to avoid looping over all files
// but looping is still much better than rebuilding whole list
var file = Fileslist.FirstOrDefault(c => String.Equals(c.FullPath, e.FullPath, StringComparison.OrdinalIgnoreCase));
if (file != null) {
if (e.ChangeType == WatcherChangeTypes.Deleted)
; // delete
else
; // update file properties
}
else {
// add new, unless event is delete
}
}
}
private void FileOnRenamed(object sender, RenamedEventArgs e) {
lock (fileListLock) {
// better use dictionary to avoid looping over all files
var file = Fileslist.FirstOrDefault(c => String.Equals(c.FullPath, e.OldFullPath, StringComparison.OrdinalIgnoreCase));
if (file != null) {
file.FullPath = e.FullPath;
}
else {
// add new
}
}
}
public void RefreshFilesList() {
// you need to lock here, because there is a race condition between this method and FileOnRenamed \ FileOnChanged,
// and you might lose some updates or get duplicates.
lock (fileListLock) {
// update ObservableCollection on UI thread
OnUIThreadDo(() => {
Fileslist.Clear();
});
DirectoryInfo dir = new DirectoryInfo(filewatcher.Path);
int nof = 0;
var files = new List<Files>();
// just use EnumerateFiles
foreach (FileInfo file in dir.EnumerateFiles("*.txt")) {
nof++;
int tmp = nof;
// if you are working with UI (that is most likely the case if you use ObservableCollection) -
// you need to update that collection from UI thread if you have bound controls
files.Add(new Files() {
FileId = tmp,
FullPath = file.FullName,
FileChanged = file.LastWriteTime,
FileCreated = file.CreationTime,
});
// don't do that
// NotifyPropertyChanged("fileslist");
}
// publish them all to collection on UI thread
OnUIThreadDo(() => {
foreach (var file in files)
Fileslist.Add(file);
});
}
}
private void OnUIThreadDo(Action a) {
if (Application.Current.CheckAccess())
a();
else
Application.Current.Dispatcher.BeginInvoke(a);
}
public void Dispose() {
DisposeWatcher();
}
private void DisposeWatcher() {
if (filewatcher != null) {
filewatcher.EnableRaisingEvents = false;
filewatcher.Created -= FileOnchanged;
filewatcher.Deleted -= FileOnchanged;
filewatcher.Changed -= FileOnchanged;
filewatcher.Renamed -= FileOnRenamed;
filewatcher.Dispose();
}
}
}
public class Files : INotifyPropertyChanged
{ // implement INotifyPropertyChanged, because you need to reflect property changes in UI
public int FileId { get; set; }
public string FullPath { get; set; }
public string FileName => Path.GetFileName(FullPath);
public DateTime FileChanged { get; set; }
public DateTime FileCreated { get; set; }
public string OnlyNameWithoutExtension => Path.GetFileNameWithoutExtension(FullPath);
}

Reconnect vpn. Windows service

I've been trying to implement a windows service that would keep vpn connection alive. I've found that it is possible to achieve using DotRas library by subscribing to RasConnectionWatcher.Disconnected event:
public class SampleService {
public SampleService() {
this.shutdownEvent = new ManualResetEvent(false);
this.connectionWatcher = new RasConnectionWatcher();
this.connectionWatcher.Disconnected += onVpnDisconnected;
}
// redial
void onVpnDisconnected(Object sender, RasConnectionEventArgs e) {
this.DialUp();
}
void DialUp() {
// connection setup is omitted
// keep the handle of the connection
this.connectionWatcher.Handle = dialer.Dial();
}
public void Start() {
this.thread = new Thread(WorkerThreadFunc);
this.thread.IsBackground = true;
this.thread.Start();
}
public void Stop() {
this.shutdownEvent.Set();
if(!this.thread.Join(3000)) this.thread.Abort();
}
private void WorkerThreadFunc() {
this.DialUp();
while(!this.shutdownEvent.WaitOne(0)) Thread.Sleep(1000);
}
}
When I start the service vpn connection opens without any problem, but when I manually interrupt the connection it seems that Disconnected event doesn't fire up.
solution 1
Found similar question/answer here:
http://social.msdn.microsoft.com/Forums/en-US/56ab2d0d-2425-4d76-81fc-04a1e1136141/ras-connection-application-and-service?forum=netfxnetcom.
solution 2
Got an answer from Jeff Winn yesterday:
https://dotras.codeplex.com/discussions/547038
public class VpnKeeperService : IService {
private ManualResetEvent shutdownEvent;
private RasConnectionWatcher connWatcher;
private Thread thread;
public VpnKeeperService() {
this.shutdownEvent = new ManualResetEvent(false);
this.connWatcher = new RasConnectionWatcher();
this.connWatcher.EnableRaisingEvents = true;
this.connWatcher.Disconnected += (s, args) => { this.DialUp(); };
}
Boolean DialUp() {
try {
using(var phoneBook = new RasPhoneBook()) {
var name = VpnConfig.GetConfig().ConnectionName;
var user = VpnConfig.GetConfig().Username;
var pass = VpnConfig.GetConfig().Password;
var pbPath = VpnConfig.GetConfig().PhoneBookPath;
phoneBook.Open(pbPath);
var entry = phoneBook.Entries.FirstOrDefault(e => e.Name.Equals(name));
if(entry != null) {
using(var dialer = new RasDialer()) {
dialer.EntryName = name;
dialer.Credentials = new NetworkCredential(user, pass);
dialer.PhoneBookPath = pbPath;
dialer.Dial();
}
}
else throw new ArgumentException(
message: "entry wasn't found: " + name,
paramName: "entry"
);
}
return true;
}
catch {
// log the exception
return false;
}
}
public void Start() {
this.thread = new Thread(WorkerThreadFunc);
this.thread.Name = "vpn keeper";
this.thread.IsBackground = true;
this.thread.Start();
}
public void Stop() {
this.shutdownEvent.Set();
if(!this.thread.Join(3000)) {
this.thread.Abort();
}
}
private void WorkerThreadFunc() {
if(this.DialUp()) {
while(!this.shutdownEvent.WaitOne(0)) {
Thread.Sleep(1000);
}
}
}
}
Hope it helps someone.

update a richtextbox from a static class

I have the following code:
namespace SSS.RemoteTruckService
{
public partial class Startup : Form
{
private Timer _gpsTimer;
private Timer _ppsTimer;
private Timer _creditCardTimer;
private Timer _iniTimer;
public string Message
{
get { return richTextBox_Message.Text; }
set
{
richTextBox_Message.Invoke((MethodInvoker)(()
=> richTextBox_Message.Text = DateTime.Now + " " +
value + Environment.NewLine + richTextBox_Message.Text));
}
}
public Startup()
{
InitializeComponent();
}
private void ButtonStartClick(object sender, EventArgs e)
{
StartRemoteTruck();
}
private void ButtonPauseClick(object sender, EventArgs e)
{
if (_gpsTimer.Enabled) _gpsTimer.Enabled = false;
if (_ppsTimer.Enabled) _ppsTimer.Enabled = false;
if (_creditCardTimer.Enabled) _creditCardTimer.Enabled = false;
if (_iniTimer.Enabled) _iniTimer.Enabled = false;
ProcessIniFile.StopProcess();
}
public void StartRemoteTruck()
{
Message = "RemoteTruck started.";
if (Settings.GlobalSettings == null)
{
Message = "GlobalSettings was null or not loaded. Cannot continue.";
Logging.Log("GlobalSettings was null or not loaded. Cannot continue.", "RemoteTruck", Apps.RemoteTruckService);
Environment.Exit(0);
}
if (Settings.GlobalSettings.IniFileWatcherEnabled)
{
ProcessIniFile.StartProcess();
}
CreateTimers();
}
And in the ProcessIniFile.StartProcess() I have the code:
namespace SSS.RemoteTruckService.inifile
{
public static class ProcessIniFile
{
private static DateTime _iniLastWriteTime;
private static readonly string Inifile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "sss.ini");
private static FileSystemWatcher _watcher;
public static void StartProcess()
{
ReadIniFile();
SaveCurrentIniReadings();
CreateIniFileWatcher();
}
public static void StopProcess()
{
if (_watcher != null)
{
_watcher.EnableRaisingEvents = false;
_watcher = null;
}
}
private static void CreateIniFileWatcher()
{
_watcher = new FileSystemWatcher
{
Path = Environment.GetFolderPath(Environment.SpecialFolder.Windows),
NotifyFilter = NotifyFilters.LastWrite,
Filter = "sss.ini"
};
_watcher.Changed += SssIniWatcherChanged;
_watcher.EnableRaisingEvents = true;
}
I'd like to pass back the the calling form the status of the reads of the file watcher.
Maybe I'm overthinking this, but if I want to add to the Message on the main form, how do I get to it?
You can use Events for that. Your process can send events and your form can handle them.
More info: http://msdn.microsoft.com/en-us/library/awbftdfh.aspx
The simple but not pretty way I like to use is to make that part of the form static as well. For example, creating a static variable WriteMessage, and in your Form Load or Startup(), you can set it:
WriteMessage = (s) => Message = s;
Sure this has some issues, but it's a quick way to get it done. One of those issues is that, you may need to use Dispatcher.invoke if you're not on the UI thread.

Missing events on catching from FileSystemWatcher C#

I'm trying to create a simple app, what moves all files writed to some directory to other directory. That's my problem: if i write other than 10000 files at once in my directory(small .txt files over 1KB) - some of them not handling to move on output directory. I'm using FileSystemWatcher events handler to solve this problem. Here is my code example:
Class MyProgramm
{
void Process(Object o, FileSystemEventArgs e)
{
//do something with e.Name file
}
void main()
{
var FSW = New FileSystemWatcher{Path = "C:\\InputDir"};
FSW.Created += Process;
FSW.EnableRisingEvents = true;
Thread.Sleep(Timeout.Infinite);
}
}
Finally, we got some files processed, but some of written files stays unprocessed..
Any suggestions?
I had similar issues with the FileSystemWatcher. It seemed to "drop the ball" quite regularly. I went for an alternative solution by extending "ServiceBase", which has been working consistently since it went live as a windows service. Hope this helps:
public partial class FileMonitor : ServiceBase
{
private Timer timer;
private long interval;
private const string ACCEPTED_FILE_TYPE = "*.csv";
public FileMonitor()
{
this.ServiceName = "Service";
this.CanStop = true;
this.CanPauseAndContinue = true;
this.AutoLog = true;
this.interval = long.Parse(1000);
}
public static void Main()
{
ServiceBase.Run(new FileMonitor());
}
protected override void OnStop()
{
base.OnStop();
this.timer.Dispose();
}
protected override void OnStart(string[] args)
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
this.timer = new Timer(new TimerCallback(ProcessNewFiles), autoEvent, interval, Timeout.Infinite);
}
private void ProcessNewFiles(Object stateInfo)
{
DateTime start = DateTime.Now;
DateTime complete = DateTime.Now;
try
{
string directoryToMonitor = "c:\mydirectory";
DirectoryInfo feedDir = new DirectoryInfo(directoryToMonitor);
FileInfo[] feeds = feedDir.GetFiles(ACCEPTED_FILE_TYPE, SearchOption.TopDirectoryOnly);
foreach (FileInfo feed in feeds.OrderBy(m => m.LastWriteTime))
{
// Do whatever you want to do with the file here
}
}
finally
{
TimeSpan t = complete.Subtract(start);
long calculatedInterval = interval - t.Milliseconds < 0 ? 0 : interval - t.Milliseconds;
this.timer.Change(calculatedInterval, Timeout.Infinite);
}
}
}

Categories

Resources