Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dbeuchler
Created January 12, 2018 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dbeuchler/e9f590294a6e68b7b21dade44dd132c4 to your computer and use it in GitHub Desktop.
Save dbeuchler/e9f590294a6e68b7b21dade44dd132c4 to your computer and use it in GitHub Desktop.
Network file system watcher
using System;
using System.ComponentModel;
using System.IO;
using System.Timers;
namespace NetFileSystemWatcher
{
public enum ConnectionState
{
/// <summary>
/// Connection to filesystem is OK
/// </summary>
Connected,
/// <summary>
/// Connection to filesystem has failed.
/// </summary>
Disconnected,
/// <summary>
/// Pseudo state to indicate that file watcher has just been reconnected.
/// File watcher will never be in this state.
/// </summary>
Reconnected
}
/// <summary>
/// Listens to the file system change notifications and raises events when a network directory, or file in a network directory, changes.
/// Use <see cref="FileSystemWatcher"/> for monitoring non network directory.
/// </summary>
[DesignerCategory("Code")] // Prevent Visual Studio from viewing as a component
public class NetFileSystemWatcher : FileSystemWatcher
{
private const int DefaultTimeout = 60 * 30; // Default 30 minutes between
private readonly object _lock = new object();
private Timer _timer;
private TimeSpan _currentTimeout;
/// <summary>
/// Returns the current state of the FileSystemWatcher
/// </summary>
public ConnectionState ConnectionState { get; private set; }
/// <summary>
/// Initializes a new instance of the NetFileSystemWatcher class.
/// </summary>
public NetFileSystemWatcher()
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the NetFileSystemWatcher class, given the specified directory to monitor.
/// </summary>
/// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</param>
public NetFileSystemWatcher(string path) : base(path)
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the NetFileSystemWatcher class, given the specified directory and type of files to monitor.
/// </summary>
/// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</param>
/// <param name="filter">The type of files to watch. For example, "*.txt" watches for changes to all text files.</param>
public NetFileSystemWatcher(string path, string filter) : base(path, filter)
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the NetFileSystemWatcher.
/// </summary>
/// <param name="timeout">When there has been no activity for this period of time, the connection will be checked.</param>
public NetFileSystemWatcher(TimeSpan timeout)
{
Initialize(timeout);
}
/// <summary>
/// Initializes a new instance of the NetFileSystemWatcher, given the specified directory.
/// </summary>
/// <param name="timeout">When there has been no activity for this period of time, the connection will be checked.</param>
/// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</param>
public NetFileSystemWatcher(TimeSpan timeout, string path) : base(path)
{
Initialize(timeout);
}
/// <summary>
/// Initializes a new instance of the NetFileSystemWatcher, given the specified directory and type of files to monitor.
/// </summary>
/// <param name="timeout">When there has been no activity for this period of time, the connection will be checked.</param>
/// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</param>
/// <param name="filter">The type of files to watch. For example, "*.txt" watches for changes to all text files.</param>
public NetFileSystemWatcher(TimeSpan timeout, string path, string filter) : base(path, filter)
{
Initialize(timeout);
}
/// <summary>
/// Initializes with the default timeout
/// </summary>
private void Initialize()
{
Initialize(TimeSpan.FromSeconds(DefaultTimeout));
}
private void Initialize(TimeSpan timeout)
{
if (timeout.TotalMilliseconds < 1000)
throw new ArgumentException("Value too low", nameof(_currentTimeout));
_currentTimeout = timeout;
ConnectionState = ConnectionState.Connected;
Error += HandleErrors;
Changed += ResetTimer;
Deleted += ResetTimer;
Created += ResetTimer;
Renamed += ResetTimer;
_timer = new Timer(_currentTimeout.TotalMilliseconds);
_timer.Elapsed += OnTimerElapsed;
_timer.Enabled = true;
}
private void ResetTimer(object sender, FileSystemEventArgs e)
{
// Reset timer
_timer.Enabled = false;
_timer.Enabled = true;
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (_timer != null)
{
Error -= HandleErrors;
Changed -= ResetTimer;
Deleted -= ResetTimer;
Created -= ResetTimer;
Renamed -= ResetTimer;
_timer.Enabled = false;
_timer.Elapsed -= OnTimerElapsed;
_timer = null;
}
base.Dispose(disposing);
}
private void OnTimerElapsed(object sender, ElapsedEventArgs args)
{
if (!EnableRaisingEvents && ConnectionState != ConnectionState.Disconnected)
return;
_timer.Enabled = false;
try
{
EnableRaisingEvents = false;
EnableRaisingEvents = true;
SetConnectionState(ConnectionState.Connected);
}
catch
{
SetConnectionState(ConnectionState.Disconnected);
}
_timer.Enabled = true;
}
private void HandleErrors(object sender, ErrorEventArgs e)
{
SetConnectionState(ConnectionState.Disconnected);
}
private void SetConnectionState(ConnectionState newState)
{
if (ConnectionState != newState)
{
bool stateChanged = false;
lock (_lock)
{
if (ConnectionState != newState)
{
ConnectionState = newState;
stateChanged = true;
}
}
if (stateChanged)
{
ConnectionStateChanged?.Invoke(this, newState);
}
}
else
{
if (newState == ConnectionState.Connected)
{
ConnectionStateChanged?.Invoke(this, ConnectionState.Reconnected);
}
}
}
/// <summary>
/// Occurs when connection to the network folder is lost or reconnected.
/// </summary>
public event EventHandler<ConnectionState> ConnectionStateChanged;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment