This is my first attempt at trying to write a "monitor" class to determine if a UNC path is available. I need the monitor to not block the main thread and to also event when the UNC is toggled UP/DOWN so that I can respond to that event.
I'm looking for:
- Best practice suggestions
- Am I doing this properly? Is there a more efficient way?
- Will there be threads left alive? will I eat into the pool until it starves?
- Other comments suggestions related to this code or programming context
public class NetworkPathMonitor
{
public event EventHandler<PathAvailabilityChangedArgs> PathAvailabilityChanged;
public event EventHandler Started;
public event EventHandler Stopping;
public event EventHandler Stopped;
public event EventHandler CheckingStatus;
protected virtual void OnStopping(object sender, EventArgs e)
{
EventHandler handler = Stopping;
if (handler != null)
handler(sender, e);
}
protected virtual void OnCheckingStatus(object sender, EventArgs e)
{
EventHandler handler = CheckingStatus;
if (handler != null)
handler(sender, e);
}
protected virtual void OnStopped(object sender, EventArgs e)
{
EventHandler handler = Stopped;
if (handler != null)
handler(sender, e);
}
protected virtual void OnStarted(object sender, EventArgs e)
{
EventHandler handler = Started;
if (handler != null)
handler(sender, e);
}
protected virtual void OnPathAvailabilityChanged(object sender, PathAvailabilityChangedArgs e)
{
EventHandler<PathAvailabilityChangedArgs> handler = PathAvailabilityChanged;
if (handler != null)
handler(sender, e);
}
private PathState CurrentState { get; set; }
private CancellationTokenSource TokenSource { get; set; }
private AutoResetEvent IsStopping { get; set; }
public string PathToMonitor { get; set; }
public int Interval { get; set; }
public NetworkPathMonitor(string pathToMonitor, int interval, PathState expectedState = PathState.Up)
{
this.CurrentState = expectedState;
this.Interval = interval;
this.PathToMonitor = pathToMonitor;
}
public void Stop()
{
OnStopping(this, EventArgs.Empty);
TokenSource.Cancel();
}
public void Start()
{
IsStopping = new AutoResetEvent(false);
TokenSource = new CancellationTokenSource();
var t = Task.Factory.StartNew(() =>
{
OnStarted(this, EventArgs.Empty);
TimeSpan waitInterval = TimeSpan.FromMilliseconds(Interval);
while (!IsStopping.WaitOne(waitInterval))
{
if (this.TokenSource.IsCancellationRequested)
{
//Is this how to properly stop the signal?
IsStopping.Set();
IsStopping.Dispose();
OnStopped(this, EventArgs.Empty);
break;
}
OnCheckingStatus(this, EventArgs.Empty);
CheckPathStatus();
}
}, TokenSource.Token);
}
private void CheckPathStatus()
{
//this is synchronous. We just have to wait for it to timeout.
var currentState = Directory.Exists(PathToMonitor) ? PathState.Up : PathState.Down;
var shouldEvent = currentState != CurrentState;
CurrentState = currentState;
if (shouldEvent)
{
OnPathAvailabilityChanged(this, new PathAvailabilityChangedArgs() { Path = PathToMonitor, PathState = CurrentState });
}
}
}
public enum PathState
{
Up,
Down
}
public class PathAvailabilityChangedArgs : EventArgs
{
public string Path { get; set; }
public PathState PathState { get; set; }
public PathAvailabilityChangedArgs() { }
public PathAvailabilityChangedArgs(string path)
{
Path = path;
}
}