Created
January 12, 2018 10:38
-
-
Save dbeuchler/e9f590294a6e68b7b21dade44dd132c4 to your computer and use it in GitHub Desktop.
Network file system watcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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