├── .gitattributes
├── AltComparison.md
├── FileSystemWatcherAlts.sln
├── FileSystemWatcherAlts.sln.DotSettings.user
├── FileSystemWatcherAlts
├── FileSystemOverseer.cs
├── FileSystemWatcherAlts.csproj
├── IFileSystemWatcher.cs
├── Icon
│ └── noun_160432_cc.png
├── Polling
│ ├── FileSystemPoller.cs
│ ├── IFileSystemPoller.cs
│ └── PollingType.cs
├── Properties
│ └── AssemblyInfo.cs
├── Utils
│ ├── Extentions
│ │ ├── CollectionsExtentions.cs
│ │ ├── DirectoryExtentions.cs
│ │ └── ExceptionsExtentions.cs
│ ├── FileSystemFakeWatcher.cs
│ ├── WatcherErrorHandlingPolicy.cs
│ └── WatcherErrorHandlingType.cs
├── Wrappers
│ ├── FileSystemAutoRefreshingWatcher.cs
│ ├── FileSystemRefreshableWatcher.cs
│ ├── FileSystemWatcherAdapter.cs
│ └── FileSystemWatcherWrapper.cs
└── packages.config
├── LICENSE
├── README.md
└── packages
└── Polly.2.2.3
├── Polly.2.2.3.nupkg
└── lib
├── net35
├── Polly.dll
└── Polly.xml
├── net40
├── Polly.dll
└── Polly.xml
├── net45
├── Polly.dll
└── Polly.xml
└── portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1
├── Polly.dll
└── Polly.xml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/AltComparison.md:
--------------------------------------------------------------------------------
1 | | | |FileSystemWatcher|FileSystemRefreshableWatcher|FileSystemAutoRefreshingWatcher|FileSystemPoller|FileSystemOverseer |
2 | |------------- | -------------| -------------|-------------| -------------|-------------| -------------|
3 | |**Supported Events**|**Created**|TRUE|TRUE|TRUE|TRUE|TRUE|
4 | | |**Deleted**|TRUE|TRUE|TRUE|TRUE|TRUE|
5 | | |**Changed**|TRUE|TRUE|TRUE|FALSE|TRUE\*|
6 | | |**Renamed**|TRUE|TRUE|TRUE|FALSE|TRUE\*|
7 | | |**Error**|TRUE|TRUE|TRUE|TRUE|TRUE|
8 | |**Issues Recovery**|**Remote Host Disconnected**|Breaks|User can refresh|Triggers watcher refresh|Continues when available|Triggers watcher refresh|
9 | | |**Remote Folder Deleted**|Breaks|User can refresh|Triggers watcher refresh|Continues when available|Triggers watcher refresh|
10 | | |**Internal Buffer Overflow**|Misses Files|Misses Files|Misses Files|No effect|Triggers polling|
11 | | |**Local Folder Deleted**|Breaks|User can refresh|User can refresh|Continues when available|Triggers watcher refresh|
12 |
13 |
14 | \* Supported while the internal buffer doesn't overflow. Falls back to Created/Deleted events instead of renames if it does.
15 |
16 | **A few rules of thumb:**
17 |
18 | * If you are not expecting heavy loads, consider using FileSystemAutoRefreshingWatcher. It provides the most reliability and lowest overhead for that case.
19 | * If you need "Renamed" or "Changed" update events the FileSystemPoller can't help you as it doesn't monitor them.
20 | * If you need reliability at all costs use FileSytemOverseer. Its overhead is higher than the other alternatives because it utilizes both a FileSystemAutoRefreshingWatcher and a FileSystemPoller
21 | but the combination of both gurantees the most immediate and precise reports in this library.
22 |
--------------------------------------------------------------------------------
/FileSystemWatcherAlts.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystemWatcherAlts", "FileSystemWatcherAlts\FileSystemWatcherAlts.csproj", "{195F032D-DA21-40A0-ABFF-6FC4887A6839}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {195F032D-DA21-40A0-ABFF-6FC4887A6839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {195F032D-DA21-40A0-ABFF-6FC4887A6839}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {195F032D-DA21-40A0-ABFF-6FC4887A6839}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {195F032D-DA21-40A0-ABFF-6FC4887A6839}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/FileSystemWatcherAlts.sln.DotSettings.user:
--------------------------------------------------------------------------------
1 |
2 | <AssemblyExplorer>
3 | <Assembly Path="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.Data.DataSetExtensions.dll" />
4 | <Assembly Path="c:\users\shai\documents\visual studio 2015\Projects\FileSystemWatcherAlts\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll" />
5 | </AssemblyExplorer>
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/FileSystemOverseer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Runtime.InteropServices;
7 | using System.Threading.Tasks;
8 | using FileSystemWatcherAlts.Polling;
9 | using FileSystemWatcherAlts.Utils;
10 | using FileSystemWatcherAlts.Utils.Extentions;
11 | using FileSystemWatcherAlts.Wrappers;
12 |
13 | namespace FileSystemWatcherAlts
14 | {
15 | [DebuggerDisplay("Path = {Path}, Filter = {Filter}, EnableRaisingEvents = {_enableRaisingEvents}")]
16 | ///
17 | /// A FilleSystemWatcher wrapper which detects common FileSystemWatcher issues and resolves them.
18 | /// also performs periodic polling to increase reliability.
19 | ///
20 | public class FileSystemOverseer : FileSystemAutoRefreshingWatcher
21 | {
22 | #region Fields
23 |
24 | private readonly IFileSystemPoller _poller;
25 |
26 | private bool _enableRaisingEvents;
27 |
28 | private readonly object _reportedFilesLock;
29 | private readonly HashSet _reportedItems;
30 |
31 | #endregion
32 |
33 | #region Properties
34 |
35 | ///
36 | /// Defines a delay (in milliseconds) between processing poller reports.
37 | /// The main reason to delay such reports is to allow the more descriptive reports of the watcher to be processed.
38 | ///
39 | [Browsable(false)]
40 | public int PollerReportsDelay { get; set; } = 100;
41 |
42 | public override bool EnableRaisingEvents
43 | {
44 | get
45 | {
46 | return _enableRaisingEvents;
47 | }
48 | set
49 | {
50 | _enableRaisingEvents = value;
51 | InternalWatcher.EnableRaisingEvents = value;
52 | _poller.EnableRaisingEvents = value;
53 | }
54 | }
55 | public override string Filter
56 | {
57 | get
58 | {
59 | return InternalWatcher.Filter;
60 | }
61 | set
62 | {
63 | InternalWatcher.Filter = value;
64 | _poller.Filter = value;
65 | }
66 | }
67 | public override bool IncludeSubdirectories
68 | {
69 | get
70 | {
71 | return InternalWatcher.IncludeSubdirectories;
72 | }
73 | set
74 | {
75 | bool lastEREvalue = _enableRaisingEvents;
76 | _enableRaisingEvents = false;
77 |
78 | InternalWatcher.IncludeSubdirectories = value;
79 | _poller.IncludeSubdirectories = value;
80 | _poller.ForcePoll();
81 |
82 | _enableRaisingEvents = lastEREvalue;
83 |
84 | }
85 | }
86 | public override int InternalBufferSize
87 | {
88 | get
89 | {
90 | return InternalWatcher.InternalBufferSize;
91 | }
92 | set
93 | {
94 | InternalWatcher.InternalBufferSize = value;
95 |
96 | }
97 | }
98 | public override NotifyFilters NotifyFilter
99 | {
100 | get
101 | {
102 | return InternalWatcher.NotifyFilter;
103 | }
104 | set
105 | {
106 | InternalWatcher.NotifyFilter = value;
107 | }
108 | }
109 | public override string Path
110 | {
111 | get
112 | {
113 | return InternalWatcher.Path;
114 | }
115 | set
116 | {
117 | bool lastEREvalue = _enableRaisingEvents;
118 | _enableRaisingEvents = false;
119 |
120 | InternalWatcher.Path = value;
121 | _poller.Path = value;
122 |
123 | _enableRaisingEvents = lastEREvalue;
124 | }
125 | }
126 |
127 | #endregion
128 |
129 | #region Constructors
130 |
131 | public FileSystemOverseer(IFileSystemPoller poller, IFileSystemWatcher watcher) : base(watcher)
132 | {
133 | _reportedItems = new HashSet();
134 | _reportedFilesLock = new object();
135 |
136 | InitPollerErrorPolicies();
137 |
138 | // Initiating poller
139 | _poller = poller;
140 | if(_poller.Path != watcher.Path)
141 | {
142 | _poller.Path = watcher.Path;
143 | }
144 |
145 | EnableRaisingEvents = false;
146 |
147 | _poller.Created += OnCreatedPolled;
148 | _poller.Deleted += OnDeletedPolled;
149 | _poller.Error += OnPollerError;
150 |
151 | // Getting initial directory content by forcing a poll
152 | _poller.PollingType = PollingType.Poll;
153 | _poller.ForcePoll();
154 |
155 | // For the rest of the Overseer's lifespan, keep the poller as a 'watcher'
156 | _poller.PollingType = PollingType.Watch;
157 | }
158 |
159 | public FileSystemOverseer(IFileSystemPoller poller, FileSystemWatcher watcher) : this(poller, new FileSystemWatcherAdapter(watcher))
160 | {
161 | }
162 |
163 | public FileSystemOverseer(IFileSystemPoller poller) : this(poller, new FileSystemWatcherAdapter(poller.Path, poller.Filter))
164 | {
165 | }
166 |
167 | public FileSystemOverseer(int pollingInterval) : this(new FileSystemPoller(pollingInterval), new FileSystemWatcher())
168 | {
169 | }
170 |
171 | public FileSystemOverseer(int pollingInterval, string path) : this(new FileSystemPoller(pollingInterval, path), new FileSystemWatcher(path))
172 | {
173 | }
174 |
175 | public FileSystemOverseer(int pollingInterval, string path, string filter) : this(new FileSystemPoller(pollingInterval, path, filter), new FileSystemWatcher(path, filter))
176 | {
177 | }
178 |
179 | private void InitPollerErrorPolicies()
180 | {
181 | var dirNotFoundPolicy = new WatcherErrorHandlingPolicy(typeof(DirectoryNotFoundException),
182 | "When the poller indicates a 'directory not found' exception check if it's the main watched directory or sub-dir." +
183 | "If it's the main directory - refresh the watcher.",
184 | exception => (exception as DirectoryNotFoundException)?.Path() == Path
185 | ? WatcherErrorHandlingType.Refresh | WatcherErrorHandlingType.Swallow
186 | : WatcherErrorHandlingType.Forward);
187 |
188 | var unAuthPolicy = new WatcherErrorHandlingPolicy(typeof(UnauthorizedAccessException),
189 | "When the poller indicates an 'unauthorized access' exception check if it's access was denied to the main watched directory or file/sub-dir." +
190 | "If it's the main directory - refresh the watcher.",
191 | exception => (exception as UnauthorizedAccessException)?.Path() == Path
192 | ? WatcherErrorHandlingType.Refresh | WatcherErrorHandlingType.Swallow
193 | : WatcherErrorHandlingType.Forward);
194 |
195 | AddPolicy(dirNotFoundPolicy);
196 | AddPolicy(unAuthPolicy);
197 | }
198 |
199 | #endregion
200 |
201 | #region Event Handling Methods
202 |
203 | // Event handlers for the wrapped watcher and the poller (a delay)
204 | protected override void OnCreated(object sender, FileSystemEventArgs fileSystemEventArgs)
205 | {
206 | lock (_reportedFilesLock)
207 | {
208 | // If the files was already reported - return
209 | if (_reportedItems.Contains(fileSystemEventArgs.FullPath))
210 | {
211 | return;
212 | }
213 |
214 | // Other wise:
215 | // 1. Add to reported files set
216 | _reportedItems.Add(fileSystemEventArgs.FullPath);
217 | }
218 |
219 | // 2. report to subscribers
220 | if (!_enableRaisingEvents) return;
221 | base.OnCreated(sender, fileSystemEventArgs);
222 | }
223 |
224 | protected override void OnDeleted(object sender, FileSystemEventArgs fileSystemEventArgs)
225 | {
226 |
227 | lock (_reportedFilesLock)
228 | {
229 | // If the files was already reported - return
230 | if (!_reportedItems.Contains(fileSystemEventArgs.FullPath))
231 | {
232 | return;
233 | }
234 |
235 |
236 | // Other wise:
237 | // 1. Try to remove said file. If the removal fails - return
238 | if (!_reportedItems.Remove(fileSystemEventArgs.FullPath)) return;
239 | }
240 |
241 | // 2. report to subscribers
242 | if (!_enableRaisingEvents) return;
243 | base.OnDeleted(sender, fileSystemEventArgs);
244 | }
245 |
246 | protected override void OnChanged(object sender, FileSystemEventArgs fileSystemEventArgs)
247 | {
248 | if (!_enableRaisingEvents) return;
249 | base.OnChanged(sender,fileSystemEventArgs);
250 | }
251 |
252 | protected override void OnRenamed(object sender, RenamedEventArgs fileSystemEventArgs)
253 | {
254 | lock (_reportedFilesLock)
255 | {
256 | // If a file with the new name was already reported - return
257 | if (_reportedItems.Contains(fileSystemEventArgs.FullPath))
258 | {
259 | return;
260 | }
261 |
262 | // 1. If the file's old name existed in the storage - remove it
263 | if (_reportedItems.Contains(fileSystemEventArgs.OldFullPath))
264 | {
265 | _reportedItems.Remove(fileSystemEventArgs.OldFullPath);
266 | }
267 |
268 | // 2. Add new path to the reportedFiles list
269 | _reportedItems.Add(fileSystemEventArgs.FullPath);
270 | }
271 |
272 | // 3. report to subscribers
273 | if (!_enableRaisingEvents) return;
274 | base.OnRenamed(sender, fileSystemEventArgs);
275 | }
276 |
277 | protected override void OnError(object sender, ErrorEventArgs e)
278 | {
279 | var ex = e.GetException();
280 | if (ex is InternalBufferOverflowException)
281 | {
282 | _poller.ForcePoll();
283 | }
284 |
285 | base.OnError(sender, e);
286 | }
287 |
288 | // Events raised by the poller will invoke these methods first:
289 | private void OnCreatedPolled(object sender, FileSystemEventArgs fileSystemEventArgs)
290 | {
291 | Task.Delay(PollerReportsDelay).ContinueWith(task => OnCreated(sender, fileSystemEventArgs));
292 | }
293 |
294 | private void OnDeletedPolled(object sender, FileSystemEventArgs fileSystemEventArgs)
295 | {
296 |
297 | Task.Delay(PollerReportsDelay).ContinueWith(task => OnDeleted(sender, fileSystemEventArgs));
298 | }
299 |
300 | private void OnPollerError(object sender, ErrorEventArgs e)
301 | {
302 | base.OnError(sender, e);
303 | }
304 |
305 | #endregion
306 |
307 | #region IDisposeable Methods
308 |
309 | ~FileSystemOverseer()
310 | {
311 | Dispose(false);
312 | }
313 |
314 | public new void Dispose()
315 | {
316 | Dispose(true);
317 | GC.SuppressFinalize(this);
318 | }
319 |
320 | private void Dispose(bool disposing)
321 | {
322 | _poller.Created -= OnCreatedPolled;
323 | _poller.Deleted -= OnDeletedPolled;
324 | _poller.Error -= OnPollerError;
325 | _poller.Dispose();
326 |
327 | if (disposing)
328 | {
329 | base.Dispose();
330 | }
331 | }
332 |
333 | #endregion
334 |
335 | #region ICloneable Methods
336 |
337 | public override object Clone()
338 | {
339 | var clonedPoller = (IFileSystemPoller) _poller.Clone();
340 |
341 | var clonedEncapsWatcher = (IFileSystemWatcher) InternalWatcher.Clone();
342 |
343 | var clonedOverseer = new FileSystemOverseer(clonedPoller, clonedEncapsWatcher)
344 | { PollerReportsDelay = this.PollerReportsDelay };
345 |
346 | clonedOverseer.ClearPolicies();
347 | foreach (var policy in ErrorHandlingPolicies)
348 | {
349 | clonedOverseer.AddPolicy(policy);
350 | }
351 |
352 | return clonedOverseer;
353 | }
354 |
355 | #endregion
356 | }
357 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/FileSystemWatcherAlts.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {195F032D-DA21-40A0-ABFF-6FC4887A6839}
8 | Library
9 | Properties
10 | FileSystemWatcherAlts
11 | FileSystemWatcherAlts
12 | v4.5
13 | 512
14 |
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 | false
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 | ..\packages\Polly.2.2.3\lib\net45\Polly.dll
40 | True
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
75 |
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/IFileSystemWatcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace FileSystemWatcherAlts
5 | {
6 | ///
7 | /// Defines properties, events and methods for a FileSystemWatcher-like class
8 | ///
9 | public interface IFileSystemWatcher : IDisposable, ICloneable
10 | {
11 | bool EnableRaisingEvents { get; set; }
12 | string Filter { get; set; }
13 | bool IncludeSubdirectories { get; set; }
14 | int InternalBufferSize { get; set; }
15 | NotifyFilters NotifyFilter { get; set; }
16 | string Path { get; set; }
17 |
18 | event FileSystemEventHandler Changed;
19 | event FileSystemEventHandler Created;
20 | event FileSystemEventHandler Deleted;
21 | event RenamedEventHandler Renamed;
22 | event ErrorEventHandler Error;
23 |
24 | WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType);
25 | WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, int timeout);
26 | }
27 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Icon/noun_160432_cc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theXappy/FileSystemWatcherAlts/6e228ed78367cb7aca7e4aa90debb9d737584441/FileSystemWatcherAlts/Icon/noun_160432_cc.png
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Polling/FileSystemPoller.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.ComponentModel;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Text.RegularExpressions;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using FileSystemWatcherAlts.Utils.Extentions;
11 | using PathClass = System.IO.Path;
12 |
13 | namespace FileSystemWatcherAlts.Polling
14 | {
15 | [DebuggerDisplay("Path = {_path}, Filter = {_filter}, Polling = {_pollingTask!=null}, EnableRaisingEvents = {_enableRaisingEvents}")]
16 | ///
17 | /// Polls the file system and raises events when a directory, or file in a directory, changes.
18 | ///
19 | public class FileSystemPoller : IFileSystemWatcher, IFileSystemPoller
20 | {
21 | #region Events
22 |
23 | public event FileSystemEventHandler Created;
24 | public event FileSystemEventHandler Deleted;
25 | public event ErrorEventHandler Error;
26 |
27 | event FileSystemEventHandler IFileSystemWatcher.Changed
28 | {
29 | add
30 | {
31 | if(_supressNotSuppotedErrors) return;
32 |
33 | throw new NotImplementedException("Changed events are not supported by FileSystemPoller. If you are trying to wrap the poller use poller.SupressNotSupportedErrors = true to stop this exception from being thrown.");
34 | }
35 | remove
36 | {
37 | }
38 | }
39 | event RenamedEventHandler IFileSystemWatcher.Renamed
40 | {
41 | add
42 | {
43 | if (_supressNotSuppotedErrors) return;
44 |
45 | throw new NotImplementedException("Renamed events are not supported by FileSystemPoller. If you are trying to wrap the poller use poller.SupressNotSupportedErrors = true to stop this exception from being thrown.");
46 | }
47 | remove
48 | {
49 | }
50 | }
51 |
52 | #endregion
53 |
54 | #region Fields
55 |
56 | // classic watcher properties' backing fields
57 | ///
58 | /// Indicates whether the poller should raise it's events when a new notification is found
59 | ///
60 | private bool _enableRaisingEvents;
61 | ///
62 | /// Indicates what path of the directory the poller should poll from
63 | ///
64 | private string _path;
65 | ///
66 | /// An uppercase version of _path. used for string comparisons (prevents multiple ToUpper calls)
67 | ///
68 | private string _uppercasePath;
69 | ///
70 | /// Indicates whether the poller should supress it's NotSupported exceptions when subscribing to Changed/Renamed events.
71 | ///
72 | private bool _supressNotSuppotedErrors = false;
73 | ///
74 | /// Indicates whether the poller should poll subdirectories or not.
75 | ///
76 | private bool _includeSubdirectories;
77 |
78 |
79 | // basic file watching fields
80 |
81 | ///
82 | /// A FileSystemWatcher-like filter for the poller to use
83 | ///
84 | private string _filter;
85 | ///
86 | /// A regex expression created according to the _filter and used to check polled files.
87 | ///
88 | private Regex _regexFilter;
89 | ///
90 | /// Used by the polling thread to signal it has finished the initial polling.
91 | ///
92 | private readonly ManualResetEvent _initialFilesSeen;
93 | ///
94 | /// Collection of files seen in the last poll
95 | ///
96 | private IEnumerable _lastSeenFiles;
97 | ///
98 | /// Collection of directories seen in the last poll
99 | ///
100 | private IEnumerable _lastSeenDirs;
101 |
102 |
103 | // Polling related fields
104 |
105 | ///
106 | /// The task responsible for polling.
107 | ///
108 | private Task _pollingTask;
109 | ///
110 | /// Makes sure only a single thread starts/stops the polling task
111 | ///
112 | private readonly object _pollingTaskLock;
113 | ///
114 | /// Used by the polling thread to wait the timeout between polls. If set the thread stops waiting and continues.
115 | ///
116 | private readonly AutoResetEvent _pollingTimeoutEvent;
117 | ///
118 | /// Used to signal to the polling thread that it should stop execution
119 | ///
120 | private readonly ManualResetEventSlim _pollingEnabledEvent;
121 | ///
122 | /// Used by the polling thread to signal a poll was done sucessfully. The event is set afte EVERY poll.
123 | ///
124 | private readonly ManualResetEventSlim _pollDone;
125 |
126 |
127 | // WaitForChange fields
128 |
129 | ///
130 | /// Contains the number of threads waiting for notifications using the WaitForChanged methods
131 | ///
132 | private int _waiters;
133 | ///
134 | /// Used by the polling thread to signal to the waiters that a new notification is available.
135 | ///
136 | private readonly AutoResetEvent _changesWatchingEvent;
137 | ///
138 | /// Latest notification available for the WaitForChanged waiters
139 | ///
140 | private WaitForChangedResult _latestChange;
141 | ///
142 | /// Used to assert only a single thread (waiter/poller) access the _latestChange field at a time.
143 | ///
144 | private readonly object _latestChangeLocker;
145 |
146 | #endregion
147 |
148 | #region Properties
149 |
150 | ///
151 | /// Defines whether the poller acts as a 'Watcher' or as a clasic 'Poller'.
152 | ///
153 | public PollingType PollingType { get; set; }
154 |
155 | ///
156 | /// Path of the directory to monitor
157 | ///
158 | public string Path
159 | {
160 | get { return _path; }
161 | set
162 | {
163 | if (value == null) throw new NullReferenceException(nameof(Path));
164 | if (value.Length == 0) throw new ArgumentException("Path cannot be an empty string.", nameof(Path));
165 |
166 | StopPollingTask();
167 |
168 | // Add the directory seperator character to the value if it's missing
169 | if (value[value.Length-1] != PathClass.DirectorySeparatorChar)
170 | {
171 | value = value + PathClass.DirectorySeparatorChar;
172 | }
173 |
174 | _path = value;
175 | _uppercasePath = _path.ToUpperInvariant();
176 |
177 | StartPollingTask();
178 | }
179 | }
180 | ///
181 | /// Whether the poller should raise Created/Deleted/Error events
182 | ///
183 | public bool EnableRaisingEvents
184 | {
185 | get { return _enableRaisingEvents; }
186 | set
187 | {
188 | if (String.IsNullOrEmpty(_path))
189 | {
190 | throw new InvalidOperationException("No directory path was provided to the poller. Can not poll.");
191 | }
192 | if (!Directory.Exists(_path))
193 | {
194 | throw new InvalidOperationException("Directory path to poll does not exist. Path: "+_path);
195 | }
196 |
197 | if (value) // settings raising to true
198 | {
199 | _initialFilesSeen.WaitOne(); // waiting for intialization to end
200 | }
201 | _enableRaisingEvents = value;
202 | }
203 | }
204 |
205 | ///
206 | /// A file name filter to monitor the directory with. Files/Directories which does not pass the filter won't be reported.
207 | ///
208 | public string Filter
209 | {
210 | get { return _filter; }
211 | set
212 | {
213 | _filter = value;
214 |
215 | if (value == string.Empty)
216 | {
217 | _regexFilter = new Regex(".*");
218 | }
219 | else
220 | {
221 | // Turning a filesytsemwatcher filter into a regex filter
222 | // abc?.txt -> abc.\.txt
223 | // def*.bin -> def.*\.bin
224 | // *.txt -> .*\.txt
225 | // *.* -> .*\..*
226 | _regexFilter = new Regex(Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*"));
227 | }
228 |
229 | }
230 | }
231 |
232 | ///
233 | /// Whether the poller should also poll in subdirectories of the directory at Path
234 | ///
235 | public bool IncludeSubdirectories
236 | {
237 | get { return _includeSubdirectories; }
238 | set
239 | {
240 | StopPollingTask();
241 |
242 | _includeSubdirectories = value;
243 |
244 | StartPollingTask();
245 | }
246 | }
247 |
248 | int IFileSystemWatcher.InternalBufferSize { get; set; }
249 | NotifyFilters IFileSystemWatcher.NotifyFilter { get; set; }
250 |
251 | ///
252 | /// The interval to poll at.
253 | ///
254 | public int PollingInterval { get; set; }
255 |
256 | ///
257 | /// Prevents the "NotImplementedException" from being thrown when subscribing to the Renamed/Changed events.
258 | /// Set this to true when trying to wrap the Poller. The events will still not invoke but will allow subscription.
259 | ///
260 | [Browsable(false)]
261 | public bool SupressNotSupportedErrors
262 | {
263 | get { return _supressNotSuppotedErrors; }
264 | set { _supressNotSuppotedErrors=value; }
265 | }
266 |
267 | ///
268 | /// Whether any threads are currently waiting in one of the WaitForChanged overloads
269 | ///
270 | private bool ReportsExpected => Volatile.Read(ref _waiters) != 0 || EnableRaisingEvents;
271 |
272 | #endregion
273 |
274 | #region Constructors
275 |
276 | public FileSystemPoller(int pollingInterval)
277 | {
278 | _path = String.Empty;
279 |
280 | _initialFilesSeen = new ManualResetEvent(false);
281 | _lastSeenFiles = new HashSet();
282 | _lastSeenDirs = new HashSet();
283 |
284 | Filter = string.Empty;
285 |
286 | _waiters = 0;
287 | _changesWatchingEvent = new AutoResetEvent(false);
288 | _latestChangeLocker = new object();
289 | _latestChange = new WaitForChangedResult();
290 |
291 | _pollingTaskLock = new object();
292 | PollingInterval = pollingInterval;
293 | _pollDone = new ManualResetEventSlim(false);
294 | _pollingTimeoutEvent = new AutoResetEvent(false);
295 | _pollingEnabledEvent = new ManualResetEventSlim(true);
296 |
297 | PollingType = PollingType.Watch;
298 |
299 | }
300 |
301 | public FileSystemPoller(int pollingInterval, string path) : this(pollingInterval)
302 | {
303 | Path = path;
304 | StartPollingTask();
305 | }
306 |
307 | public FileSystemPoller(int pollingInterval, string path, string filter) : this(pollingInterval, path)
308 | {
309 | Filter = filter;
310 | StartPollingTask();
311 | }
312 |
313 | private void StopPollingTask()
314 | {
315 | // Check if a polling task even exist
316 | if (_pollingTask == null) return;
317 |
318 | lock (_pollingTaskLock)
319 | {
320 | if (_pollingTask == null) return;
321 |
322 | _initialFilesSeen.Set();
323 | _pollingEnabledEvent.Reset(); // Signaling for the task to quit
324 | _pollingTimeoutEvent.Set(); // Trying to speed up the task exit by interupting the 'sleep' period
325 | if (_pollingTask.Status == TaskStatus.Running)
326 | {
327 | _pollingTask.Wait();
328 | }
329 | _pollingTask = null;
330 | }
331 | }
332 |
333 | private void StartPollingTask()
334 | {
335 | // Check if a no other polling task exists
336 | if (_pollingTask != null) return;
337 |
338 | lock (_pollingTaskLock)
339 | {
340 | if (_pollingTask != null) return;
341 |
342 | _initialFilesSeen.Reset();
343 | _pollingTimeoutEvent.Reset();
344 | _pollingEnabledEvent.Set();
345 | _lastSeenFiles = new Collection();
346 | _lastSeenDirs = new Collection();
347 | _pollingTask = Task.Factory.StartNew(Poll, TaskCreationOptions.LongRunning);
348 | }
349 | }
350 |
351 | #endregion
352 |
353 | #region Polling Methods
354 |
355 | ///
356 | /// Polls the files currently in the directory
357 | ///
358 | private void PollInitialDirContent()
359 | {
360 | // Get initial content
361 | while (!_initialFilesSeen.WaitOne(1))
362 | {
363 | // Check if polling was disabled
364 | if (!_pollingEnabledEvent.Wait(1)) return;
365 |
366 | // Query files in folder
367 | IEnumerable currentFiles;
368 | IEnumerable currentFolders;
369 | if (PollCurrentFiles(out currentFiles) && PollCurrentSubDirs(out currentFolders))
370 | {
371 | _lastSeenFiles = currentFiles;
372 | _lastSeenDirs = currentFolders;
373 | _initialFilesSeen.Set();
374 | return;
375 | }
376 | else
377 | {
378 |
379 | }
380 |
381 | // Check if polling was disabled
382 | if (!_pollingEnabledEvent.Wait(1)) return;
383 |
384 | // Sleep
385 | _pollingTimeoutEvent.WaitOne(PollingInterval);
386 | }
387 | }
388 |
389 | ///
390 | /// Constantly polls the files in the path given.
391 | ///
392 | private void Poll()
393 | {
394 |
395 | // Firstly, get an idea of what the folder currently looks like.
396 | PollInitialDirContent();
397 |
398 |
399 | while (true)
400 | {
401 | // Check if polling was disabled
402 | if (!_pollingEnabledEvent.Wait(1)) break;
403 |
404 | // Sleep
405 | _pollingTimeoutEvent.WaitOne(PollingInterval);
406 |
407 | // Check if polling was disabled while waiting the timeout (which might be long)
408 | if (!_pollingEnabledEvent.Wait(1)) break;
409 |
410 | // Poll both files and directories in watched folder
411 | IEnumerable currentFiles;
412 | IEnumerable currentFolders;
413 | if (!PollCurrentFiles(out currentFiles) || !PollCurrentSubDirs(out currentFolders))
414 | {
415 |
416 | // Polling files or folders failed, continuing to next sleep
417 | continue;
418 | }
419 |
420 | ProcessPolledItems(currentFiles, currentFolders);
421 |
422 | // Inform any 'ForcePoll' threads that the poll finished
423 | _pollDone.Set();
424 | }
425 |
426 | }
427 |
428 | ///
429 | /// Proccess collections of files and folders currently polled and runs checks on them according to the polling type
430 | ///
431 | /// Files that currently exist under the polled folder
432 | /// Folders that currently exist under the polled folder
433 | private void ProcessPolledItems(IEnumerable currentFiles, IEnumerable currentFolders)
434 | {
435 | // Orginazing possible check to run each poll
436 | List actionsOnItems;
437 | if (PollingType == PollingType.Watch)
438 | {
439 | actionsOnItems = new List()
440 | {
441 | () => ReportCreatedItems(_lastSeenFiles, currentFiles), // Check for new files
442 | () => ReportCreatedItems(_lastSeenDirs, currentFolders), // Check for new folders
443 | () => ReportDeletedItems(_lastSeenFiles, currentFiles), // Check for deleted files
444 | () => ReportDeletedItems(_lastSeenDirs, currentFolders) // Check for deleted folders
445 | };
446 | }
447 | else // PollingType == PollingType.Poll
448 | {
449 | actionsOnItems = new List()
450 | {
451 | () => ReportItems(currentFiles,WatcherChangeTypes.Created), // Report current files that match the filter
452 | () => ReportItems(currentFolders,WatcherChangeTypes.Created), // Report current directories that match the filter
453 | };
454 | }
455 |
456 | // For each one of the checks above, see if there is a point even running this check (EnableRaisingEvents is true or threads are WaitingForChange-s).
457 | foreach (Action itemsCheck in actionsOnItems)
458 | {
459 | if (ReportsExpected)
460 | {
461 | itemsCheck();
462 | }
463 | }
464 |
465 | // Update "last seen files" and "last seen folders"
466 | _lastSeenFiles = currentFiles;
467 | _lastSeenDirs = currentFolders;
468 | }
469 |
470 | ///
471 | /// Forces the Poller to poll for files immediatly.
472 | ///
473 | public Task ForcePollAsync(bool returnWhenPolled = false)
474 | {
475 | return Task.Factory.StartNew(()=> ForcePoll(returnWhenPolled));
476 | }
477 |
478 | ///
479 | /// Forces the Poller to poll for files immediatly.
480 | ///
481 | public void ForcePoll()
482 | {
483 | ForcePoll(returnWhenPolled: true);
484 | }
485 |
486 | ///
487 | /// Forces the Poller to poll for files immediatly.
488 | ///
489 | public void ForcePoll(bool returnWhenPolled)
490 | {
491 | _pollingTimeoutEvent.Set();
492 | if (returnWhenPolled)
493 | {
494 | _pollDone.Reset();
495 | _pollDone.Wait();
496 | }
497 | }
498 |
499 | ///
500 | /// Polls a collection of file names in the watched folder
501 | ///
502 | /// Output variable for the files' names
503 | /// True if polling succeeded, false otherwise
504 | private bool PollCurrentFiles(out IEnumerable currentFiles)
505 | {
506 |
507 | currentFiles = null;
508 | try
509 | {
510 | currentFiles = DirectoryExtentions.GetFilesInA>(Path, IncludeSubdirectories);
511 |
512 | return true;
513 | }
514 | catch (Exception ex)
515 | {
516 |
517 | OnError(new ErrorEventArgs(ex));
518 | return false;
519 | }
520 | }
521 |
522 | ///
523 | /// Polls a collection of directories names in the watched folder
524 | ///
525 | /// Output variable for the directories' names
526 | /// True if polling succeeded, false otherwise
527 | private bool PollCurrentSubDirs(out IEnumerable currentFolders)
528 | {
529 |
530 | currentFolders = null;
531 | try
532 | {
533 | currentFolders = DirectoryExtentions.GetDirsInA>(Path, IncludeSubdirectories);
534 |
535 | return true;
536 | }
537 | catch (Exception ex)
538 | {
539 |
540 | OnError(new ErrorEventArgs(ex));
541 | return false;
542 | }
543 | }
544 |
545 | #endregion
546 |
547 | #region Files Examination Methods
548 |
549 | ///
550 | /// Compares an old and a new collection of files to see if any old items were removed. Pops the "Deleted" event for each of those items.
551 | ///
552 | /// Set of old items
553 | /// Set of new items
554 | private void ReportDeletedItems(IEnumerable originalItems, IEnumerable currentItems)
555 | {
556 |
557 | // Copy last known items to a new set
558 | ISet deletedFiles = new HashSet(originalItems);
559 | // Substract current items
560 | deletedFiles.ExceptWith(currentItems);
561 |
562 | // Runs the items through the filter and reports matching ones
563 | ReportItems(deletedFiles, WatcherChangeTypes.Deleted);
564 | }
565 |
566 | ///
567 | /// Compares an old and a new collection of files to see if any new items were added. Pops the "Created" event for each of those items.
568 | ///
569 | /// Set of old items
570 | /// Set of new items
571 | private void ReportCreatedItems(IEnumerable originalItems, IEnumerable currentItems)
572 | {
573 |
574 | // Copy current found items to a new set
575 | ISet addedItems = new HashSet(currentItems);
576 | // Substract last seen items
577 | addedItems.ExceptWith(originalItems);
578 |
579 | // Runs the items through the filter and reports matching ones
580 | ReportItems(addedItems, WatcherChangeTypes.Created);
581 | }
582 |
583 | ///
584 | /// Checks an enumerable of items with the current filter and reports those who fit.
585 | ///
586 | /// The collection of items (files/folders) to check
587 | /// The type of report to create for those items
588 | private void ReportItems(IEnumerable items, WatcherChangeTypes reportType)
589 | {
590 | foreach (var item in items)
591 | {
592 | string itemName = PathClass.GetFileName(item);
593 | if (!PassesFilter(itemName)) continue;
594 | string folder = PathClass.GetDirectoryName(item) ?? string.Empty;
595 |
596 | SignalFileChangeForWaiters(reportType, item);
597 |
598 | if (EnableRaisingEvents)
599 | {
600 | FileSystemEventArgs reportArgs = new FileSystemEventArgs(reportType, folder, itemName);
601 | switch (reportType)
602 | {
603 | case WatcherChangeTypes.Created:
604 | OnCreated(reportArgs);
605 | break;
606 | case WatcherChangeTypes.Deleted:
607 | OnDeleted(reportArgs);
608 | break;
609 | }
610 | }
611 | }
612 | }
613 |
614 | ///
615 | /// Checks if a single file name/folder name matches the currently set filter
616 | ///
617 | /// File/Folder name
618 | /// True if the name matches the filter, false otherwise.
619 | private bool PassesFilter(string item)
620 | {
621 | // returns whether *the string is not empty* && *the string matches filter*
622 | return !String.IsNullOrEmpty(item) && _regexFilter.IsMatch(item);
623 | }
624 |
625 | #endregion
626 |
627 | #region Events Raising Methods
628 |
629 | private void OnCreated(FileSystemEventArgs fileSystemEventArgs)
630 | {
631 |
632 | Created?.Invoke(this, fileSystemEventArgs);
633 | }
634 | private void OnDeleted(FileSystemEventArgs fileSystemEventArgs)
635 | {
636 |
637 | Deleted?.Invoke(this, fileSystemEventArgs);
638 | }
639 | private void OnError(ErrorEventArgs errorEventArgs)
640 | {
641 |
642 | Error?.Invoke(this, errorEventArgs);
643 | }
644 |
645 | #endregion
646 |
647 | #region WaitForChanged Methods
648 |
649 | private void SignalFileChangeForWaiters(WatcherChangeTypes type, string filePath)
650 | {
651 | if (_waiters == 0) return; // No point signaling if no one is waiting
652 |
653 | // Getting the 'relative path' of the filePath compared to the currently monitored folder path
654 | string uppercaseFilePath = filePath.ToUpperInvariant();
655 | var fileNameToReport = uppercaseFilePath.Replace(_uppercasePath, string.Empty);
656 |
657 | lock (_latestChangeLocker)
658 | {
659 | _latestChange = new WaitForChangedResult() { ChangeType = type, Name = fileNameToReport };
660 | }
661 | _changesWatchingEvent.Set();
662 | }
663 |
664 | public WaitForChangedResult WaitForChanged(WatcherChangeTypes type)
665 | {
666 | if (type == WatcherChangeTypes.Renamed ||
667 | type == WatcherChangeTypes.Changed ||
668 | type == (WatcherChangeTypes.Changed | WatcherChangeTypes.Renamed)) // Polling cannot monitor these changes
669 | {
670 | throw new NotImplementedException("File System Poller can not monitor \"Rename\" or \"Changed\" file changes.");
671 | }
672 |
673 | while (true)
674 | {
675 | Interlocked.Increment(ref _waiters);
676 | _changesWatchingEvent.WaitOne();
677 | Interlocked.Decrement(ref _waiters);
678 |
679 | WaitForChangedResult results;
680 | lock (_latestChangeLocker)
681 | {
682 | results = _latestChange;
683 | }
684 | // Check if the report fits the one the current thread is looking for
685 | if (type.HasFlag(results.ChangeType))
686 | {
687 | // It does, returning the report.
688 | return results;
689 | }
690 | else
691 | {
692 | // It doesn't.
693 | // allowing a signle other thread to examine it this report:
694 | _changesWatchingEvent.Set();
695 | // making sure the event is reset when the current thread returns to it. (If a thread is waiting it will exit after the .Set and before the .Reset)
696 | _changesWatchingEvent.Reset();
697 | }
698 | }
699 | }
700 |
701 | public WaitForChangedResult WaitForChanged(WatcherChangeTypes type, int timeout)
702 | {
703 | if (type == WatcherChangeTypes.Renamed ||
704 | type == WatcherChangeTypes.Changed ||
705 | type == (WatcherChangeTypes.Changed | WatcherChangeTypes.Renamed)) // Polling cannot monitor these changes
706 | {
707 | throw new NotImplementedException("File System Poller can not monitor \"Rename\" or \"Changed\" item changes.");
708 | }
709 |
710 | // Using this stopwatch to check I'm staying in the method longer then the timeout set
711 | Stopwatch timeInMethodStopwatch = Stopwatch.StartNew();
712 |
713 | Interlocked.Increment(ref _waiters);
714 | while (true)
715 | {
716 | int remainingTimeToWait = timeout - (int)timeInMethodStopwatch.ElapsedMilliseconds;
717 | var timedOut = !_changesWatchingEvent.WaitOne(remainingTimeToWait);
718 |
719 | if (timedOut) // wait timed out, exit method.
720 | {
721 | Interlocked.Decrement(ref _waiters);
722 | return new WaitForChangedResult() { ChangeType = type, TimedOut = true };
723 | }
724 |
725 | // wait didn't time out - check results
726 | WaitForChangedResult results;
727 | lock (_latestChangeLocker)
728 | {
729 | results = _latestChange;
730 | }
731 | // Check if the reported results match the requestsed result type.
732 | // Otherwise - continue waiting for more changes
733 | if (type.HasFlag(results.ChangeType))
734 | {
735 | Interlocked.Decrement(ref _waiters);
736 | return results;
737 | }
738 | }
739 | }
740 |
741 | #endregion
742 |
743 | #region IDisposeable Methods
744 |
745 | public void Dispose()
746 | {
747 | // Canceling polling task
748 | StopPollingTask();
749 |
750 | // Empty files/folders collections - those might get quite large
751 | _lastSeenFiles = new Collection();
752 | _lastSeenDirs = new Collection();
753 | }
754 |
755 | #endregion
756 |
757 | #region ICloneable Methods
758 |
759 | public object Clone()
760 | {
761 | var clonedPoller = new FileSystemPoller(this.PollingInterval, this.Path, this.Filter)
762 | {
763 | IncludeSubdirectories = this.IncludeSubdirectories,
764 | EnableRaisingEvents = this.EnableRaisingEvents,
765 | PollingType = this.PollingType
766 | };
767 |
768 | return clonedPoller;
769 | }
770 |
771 | #endregion
772 | }
773 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Polling/IFileSystemPoller.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Threading.Tasks;
4 |
5 | namespace FileSystemWatcherAlts.Polling
6 | {
7 | public interface IFileSystemPoller : IDisposable, ICloneable
8 | {
9 | bool EnableRaisingEvents { get; set; }
10 | string Filter { get; set; }
11 | bool IncludeSubdirectories { get; set; }
12 | string Path { get; set; }
13 | int PollingInterval { get; set; }
14 | PollingType PollingType { get; set; }
15 |
16 | event FileSystemEventHandler Created;
17 | event FileSystemEventHandler Deleted;
18 | event ErrorEventHandler Error;
19 |
20 | Task ForcePollAsync(bool returnWhenPolled);
21 | void ForcePoll();
22 | }
23 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Polling/PollingType.cs:
--------------------------------------------------------------------------------
1 | namespace FileSystemWatcherAlts.Polling
2 | {
3 | ///
4 | /// Defines how FileSystemPoller reports back to the listeners
5 | ///
6 | public enum PollingType
7 | {
8 | ///
9 | /// Watcher-like behivour. Reports NEWLY created/deleted files.
10 | ///
11 | Watch,
12 | ///
13 | /// Poller-like behivour. Reports ALL existing files in the directory in EVERY poll.
14 | ///
15 | Poll
16 | }
17 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("FileSystemWatcherAlts")]
8 | [assembly: AssemblyDescription("Alternatives for System.IO.FileSystemWatcher")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("Shai Shapira")]
11 | [assembly: AssemblyProduct("FileSystemWatcherAlts")]
12 | [assembly: AssemblyCopyright("Copyright © Shai Shapira 2015")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("195f032d-da21-40a0-abff-6fc4887a6839")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Utils/Extentions/CollectionsExtentions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace FileSystemWatcherAlts.Utils.Extentions
4 | {
5 | internal static class CollectionsExtentions
6 | {
7 | ///
8 | /// Pushes a range of items into a stack
9 | ///
10 | /// The type of items in the stack
11 | /// The stack to push into
12 | /// The items to push
13 | internal static void PushRange(this Stack stack, IEnumerable items)
14 | {
15 | foreach (var item in items)
16 | {
17 | stack.Push(item);
18 | }
19 | }
20 |
21 | ///
22 | /// Addsa a range of items into a collection
23 | ///
24 | /// The type of items in the collection
25 | /// The collection to add the items into
26 | /// The items to add
27 | internal static void AddRange(this ICollection collection, IEnumerable items)
28 | {
29 | foreach (var item in items)
30 | {
31 | collection.Add(item);
32 | }
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Utils/Extentions/DirectoryExtentions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 |
5 | namespace FileSystemWatcherAlts.Utils.Extentions
6 | {
7 | internal static class DirectoryExtentions
8 | {
9 | ///
10 | /// Gets paths of the files under a directory in a given collection type.
11 | ///
12 | /// The type of strings collection to get the paths as.
13 | /// The directory to look for files.
14 | /// Whether to include sub-directories files or not.
15 | /// A collection of file paths found under .
16 | internal static T GetFilesInA(string directory, bool includeSubDirectories = false) where T : ICollection, new()
17 | {
18 | T output = new T();
19 | output.AddRange(Directory.GetFiles(directory));
20 | if (includeSubDirectories)
21 | {
22 | Stack subDirsStack = new Stack(Directory.GetDirectories(directory));
23 | while (subDirsStack.Any())
24 | {
25 | // Get next sub-dir
26 | string nextDir = subDirsStack.Pop();
27 | // Get the dir's sub-dir and push them into the stack
28 | subDirsStack.PushRange(Directory.GetDirectories(nextDir));
29 | // Get the files in the subfolder and union them with the currentFiles set
30 | var filesInSubfolder = Directory.GetFiles(nextDir);
31 | output.AddRange(filesInSubfolder);
32 | }
33 | }
34 | else
35 | {
36 | var filesInSubfolder = Directory.GetFiles(directory);
37 | output.AddRange(filesInSubfolder);
38 | }
39 | return output;
40 | }
41 |
42 | ///
43 | /// Gets paths of the sub-directories under a directory in a given collection type.
44 | ///
45 | /// The type of strings collection to get the paths as.
46 | /// The directory to look for sub-directories.
47 | /// Whether to include sub-directories' sub-directories or not.
48 | /// A collection of directories paths found under .
49 | internal static T GetDirsInA(string directory, bool includeSubDirectories = false) where T : ICollection, new()
50 | {
51 | T output = new T();
52 | if (includeSubDirectories)
53 | {
54 | Stack subDirsStack = new Stack(Directory.GetDirectories(directory));
55 | while (subDirsStack.Any())
56 | {
57 | // Get next sub-dir
58 | string nextDir = subDirsStack.Pop();
59 | IEnumerable nextSubDirs = Directory.GetDirectories(nextDir);
60 | // Get the dir's sub-dir and push them into the stack
61 | subDirsStack.PushRange(nextSubDirs);
62 | // Get the files in the subfolder and union them with the currentFiles set
63 | output.AddRange(nextSubDirs);
64 | }
65 | }
66 | else
67 | {
68 | IEnumerable nextSubDirs = Directory.GetDirectories(directory);
69 | output.AddRange(nextSubDirs);
70 | }
71 | return output;
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Utils/Extentions/ExceptionsExtentions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace FileSystemWatcherAlts.Utils.Extentions
5 | {
6 | internal static class ExceptionsExtentions
7 | {
8 | ///
9 | /// Extracts the path of the directory in the DirectoryNotFoundException
10 | ///
11 | /// The exception
12 | /// The path of the directory
13 | internal static string Path(this DirectoryNotFoundException ex)
14 | {
15 | return GetPathFromMessage(ex.Message);
16 | }
17 |
18 | ///
19 | /// Extracts the path of the directory in the UnauthorizedAccessException
20 | ///
21 | /// The exception
22 | /// The path of the directory
23 | internal static string Path(this UnauthorizedAccessException ex)
24 | {
25 | return GetPathFromMessage(ex.Message);
26 | }
27 |
28 | private static string GetPathFromMessage(string exMessage)
29 | {
30 | int startIndex = exMessage.IndexOf('\'') + 1;
31 | int endIndex = exMessage.LastIndexOf('\'');
32 | int length = endIndex - startIndex;
33 |
34 | // Here I assert that atleast 2 apostrophe exist in the message
35 | if (length < 0) return string.Empty;
36 |
37 | return exMessage.Substring(startIndex, length);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Utils/FileSystemFakeWatcher.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace FileSystemWatcherAlts.Utils
4 | {
5 | ///
6 | /// A fake object which implements the IFileSystemWatcher interface.
7 | ///
8 | internal class FileSystemFakeWatcher : IFileSystemWatcher
9 | {
10 | #region Properties
11 |
12 | public bool EnableRaisingEvents { get; set; }
13 | public string Filter { get; set; }
14 | public bool IncludeSubdirectories { get; set; }
15 | public int InternalBufferSize { get; set; }
16 | public NotifyFilters NotifyFilter { get; set; }
17 | public string Path { get; set; }
18 |
19 | #endregion
20 |
21 | #region Events
22 |
23 | public event FileSystemEventHandler Changed
24 | {
25 | add { }
26 | remove { }
27 | }
28 |
29 | public event FileSystemEventHandler Created
30 | {
31 | add { }
32 | remove { }
33 | }
34 |
35 | public event FileSystemEventHandler Deleted
36 | {
37 | add { }
38 | remove { }
39 | }
40 |
41 | public event RenamedEventHandler Renamed
42 | {
43 | add { }
44 | remove { }
45 | }
46 |
47 | public event ErrorEventHandler Error
48 | {
49 | add { }
50 | remove { }
51 | }
52 |
53 | #endregion
54 |
55 | #region IFileSystemWatcher Methods
56 |
57 | public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType)
58 | {
59 | return new WaitForChangedResult();
60 | }
61 |
62 | public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, int timeout)
63 | {
64 | return new WaitForChangedResult();
65 | }
66 |
67 | #endregion
68 |
69 | #region IDisposable Methods
70 |
71 | public void Dispose()
72 | {
73 | }
74 |
75 | #endregion
76 |
77 | #region ICloneable Methods
78 |
79 | public object Clone()
80 | {
81 | return this;
82 | }
83 |
84 | #endregion
85 | }
86 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Utils/WatcherErrorHandlingPolicy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FileSystemWatcherAlts.Utils
4 | {
5 | ///
6 | /// Defines a policy for handling an error a FileSystemWatcher might report.
7 | ///
8 | public struct WatcherErrorHandlingPolicy
9 | {
10 | #region Properties
11 |
12 | ///
13 | /// The type of exceptions this policy is testing
14 | ///
15 | public Type ExceptionType { get; set; }
16 |
17 | ///
18 | /// A description about the policy
19 | ///
20 | public string Description { get; set; }
21 |
22 | ///
23 | /// A test to run for each exception of type to determine how the error should be handled.
24 | ///
25 | public Func Test { get; set; }
26 |
27 | #endregion
28 |
29 | #region Constructor
30 |
31 | ///
32 | /// Constructor
33 | ///
34 | /// The exception type to enforce the policy on
35 | /// Literal descirption of the policy
36 | /// A test to run for each exception of type to determine how the error should be handled.
37 | public WatcherErrorHandlingPolicy(Type exceptionType, string description,
38 | Func test)
39 | {
40 | ExceptionType = exceptionType;
41 | Description = description;
42 | Test = test;
43 | }
44 |
45 | #endregion
46 | }
47 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Utils/WatcherErrorHandlingType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FileSystemWatcherAlts.Utils
4 | {
5 | ///
6 | /// Different approachs to handle a FileSystemWatcher error.
7 | ///
8 | [Flags]
9 | public enum WatcherErrorHandlingType
10 | {
11 | ///
12 | /// Forward the error using the Error event
13 | ///
14 | Forward = 0,
15 | ///
16 | /// Do not forward the error using the Error event
17 | ///
18 | Swallow = 1,
19 | ///
20 | /// Refresh the internal watcher
21 | ///
22 | Refresh = 2,
23 | ///
24 | /// Refresh the internal watcher and do not forward the error using the Error event
25 | ///
26 | RefreshAndSwallow = 3,
27 | }
28 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Wrappers/FileSystemAutoRefreshingWatcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.IO;
5 | using System.Linq;
6 | using FileSystemWatcherAlts.Utils;
7 |
8 | namespace FileSystemWatcherAlts.Wrappers
9 | {
10 | ///
11 | /// An IFileSystemWatcher wrapper which automaticly refreshes it when specific errors occurre.
12 | ///
13 | public class FileSystemAutoRefreshingWatcher : FileSystemRefreshableWatcher
14 | {
15 | #region Fields
16 |
17 | private List _errorHandlingPolicies;
18 |
19 | #endregion
20 |
21 | #region Properties
22 |
23 | public IReadOnlyCollection ErrorHandlingPolicies => _errorHandlingPolicies;
24 |
25 | #endregion
26 |
27 | #region Constructor
28 |
29 | public FileSystemAutoRefreshingWatcher()
30 | {
31 | InitBasicPolicies();
32 | }
33 |
34 | public FileSystemAutoRefreshingWatcher(FileSystemWatcher watcher) : base(watcher)
35 | {
36 | InitBasicPolicies();
37 | }
38 |
39 | public FileSystemAutoRefreshingWatcher(IFileSystemWatcher watcher) : base(watcher)
40 | {
41 | InitBasicPolicies();
42 | }
43 |
44 | public FileSystemAutoRefreshingWatcher(string path) : base(path)
45 | {
46 | InitBasicPolicies();
47 | }
48 |
49 | public FileSystemAutoRefreshingWatcher(string path, string filter) : base(path, filter)
50 | {
51 | InitBasicPolicies();
52 | }
53 |
54 | public void InitBasicPolicies()
55 | {
56 | _errorHandlingPolicies = new List();
57 |
58 | var accessDeniedPolicy = new WatcherErrorHandlingPolicy(
59 | typeof (Win32Exception),
60 | "When an 'access denied' win32 exception occures, refresh the wrapped watcher.",
61 | exception =>
62 | (exception as Win32Exception)?.NativeErrorCode == 5 ?
63 | WatcherErrorHandlingType.RefreshAndSwallow :
64 | WatcherErrorHandlingType.Forward);
65 |
66 | var netNameDeletedPolicy = new WatcherErrorHandlingPolicy(
67 | typeof (Win32Exception),
68 | "When a 'net name deleted' win32 exception occures, refresh the wrapped watcher.",
69 | exception =>
70 | (exception as Win32Exception)?.NativeErrorCode == 64 ?
71 | WatcherErrorHandlingType.RefreshAndSwallow :
72 | WatcherErrorHandlingType.Forward);
73 |
74 | _errorHandlingPolicies.Add(accessDeniedPolicy);
75 | _errorHandlingPolicies.Add(netNameDeletedPolicy);
76 | }
77 |
78 | #endregion
79 |
80 | #region Methods
81 |
82 | ///
83 | /// Removes all currently set error handling policies
84 | ///
85 | public void ClearPolicies()
86 | {
87 | _errorHandlingPolicies.Clear();
88 | }
89 |
90 | ///
91 | /// Tries to remove a specific error handling policy
92 | ///
93 | /// The policy to remove
94 | ///
95 | /// true if policy is successfully removed; otherwise, false. This method also returns
96 | /// false if policy was not found in the policies collection.
97 | ///
98 | public bool RemovePolicy(WatcherErrorHandlingPolicy pol)
99 | {
100 | return _errorHandlingPolicies.Remove(pol);
101 | }
102 |
103 | ///
104 | /// Adds an error handling policy
105 | ///
106 | ///
107 | public void AddPolicy(WatcherErrorHandlingPolicy pol)
108 | {
109 | _errorHandlingPolicies.Add(pol);
110 | }
111 |
112 | ///
113 | /// Inoked when the wrapped watcher throws an exception. The exception is tested with the existing policies
114 | /// and handled according to the tests results.
115 | ///
116 | /// Raiser of the event
117 | /// Error event args
118 | protected override void OnError(object sender, ErrorEventArgs e)
119 | {
120 | Exception ex = e.GetException();
121 | Type exType = ex.GetType();
122 | WatcherErrorHandlingType exHandling = WatcherErrorHandlingType.Forward;
123 |
124 | // Testing all relevant policies according to the exception type
125 | foreach (var relevantPolicy in ErrorHandlingPolicies.Where(policy => policy.ExceptionType == exType))
126 | {
127 | exHandling |= relevantPolicy.Test(ex);
128 | }
129 |
130 | // Check the policies test results.
131 |
132 | // If ANY of the policies requested a refresh - a refresh will be invoked
133 | if (exHandling.HasFlag(WatcherErrorHandlingType.Refresh))
134 | {
135 | // Tries to refresh. If a refresh is already in progress, the thread returns.
136 | var refreshTask = RefreshAsync(returnWhenRefreshed: false);
137 | }
138 |
139 | // If NONE of the policies requested a swallow - the error will be forwarded
140 | // (if any of them DID request a swallow, the error will be swallowed)
141 | if (!exHandling.HasFlag(WatcherErrorHandlingType.Swallow))
142 | {
143 | base.OnError(sender, e);
144 | }
145 | }
146 |
147 | #endregion
148 |
149 | #region ICloneable Methods
150 |
151 | public override object Clone()
152 | {
153 | IFileSystemWatcher clonedEncapsWatcher = InternalWatcher.Clone() as IFileSystemWatcher;
154 | FileSystemAutoRefreshingWatcher clonedAutoRefreshingWatcher = new FileSystemAutoRefreshingWatcher(clonedEncapsWatcher);
155 | // Add current refresher's policies to the cloned one
156 | clonedAutoRefreshingWatcher.ClearPolicies();
157 | foreach (var policy in _errorHandlingPolicies)
158 | {
159 | clonedAutoRefreshingWatcher.AddPolicy(policy);
160 | }
161 | return clonedAutoRefreshingWatcher;
162 | }
163 |
164 | #endregion
165 | }
166 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Wrappers/FileSystemRefreshableWatcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.ComponentModel;
4 | using System.IO;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using FileSystemWatcherAlts.Utils;
8 | using Polly;
9 |
10 | namespace FileSystemWatcherAlts.Wrappers
11 | {
12 | ///
13 | /// An IFileSystemWatcher wrapper which allows refreshing the watcher for when it ceases to work due to a problem.
14 | ///
15 | public class FileSystemRefreshableWatcher : FileSystemWatcherWrapper
16 | {
17 | #region Fields
18 |
19 | ///
20 | /// A collection of ManualResetEvents of the threads currently waiting for a refresh to finish
21 | ///
22 | private readonly ConcurrentDictionary _waitingThreadsEvents;
23 | ///
24 | /// Used to synchronize between different threads that try to refresh the watcher at the same time
25 | /// Only the one who successfully entered this object is allowed to refresh.
26 | ///
27 | private readonly object _refreshLock;
28 |
29 | private readonly CancellationTokenSource _refreshTokenSource;
30 |
31 | #endregion
32 |
33 | #region Properties
34 |
35 | ///
36 | /// The amount of time in milliseconds to wait between refresh attemps on the watcher.
37 | ///
38 | [Browsable(false)]
39 | public int RefreshAttempInterval { get; set; } = 500;
40 |
41 | ///
42 | /// Wether the watcher is currently refreshing or not.
43 | ///
44 | public bool IsRefreshing { get; private set; }
45 |
46 | #endregion
47 |
48 | #region Events
49 |
50 | public event EventHandler Refreshed;
51 |
52 | #endregion
53 |
54 | #region Constructors
55 |
56 | public FileSystemRefreshableWatcher(IFileSystemWatcher watcher) : base(watcher)
57 | {
58 | _refreshTokenSource = new CancellationTokenSource();
59 | _waitingThreadsEvents = new ConcurrentDictionary();
60 | IsRefreshing = false;
61 | _refreshLock = new object();
62 | }
63 | public FileSystemRefreshableWatcher(FileSystemWatcher watcher) : this(new FileSystemWatcherAdapter(watcher))
64 | {
65 | }
66 | public FileSystemRefreshableWatcher() : this(new FileSystemWatcher())
67 | {
68 | }
69 | public FileSystemRefreshableWatcher(string path) : this(new FileSystemWatcher(path))
70 | {
71 | }
72 | public FileSystemRefreshableWatcher(string path, string filter) : this(new FileSystemWatcher(path, filter))
73 | {
74 | }
75 |
76 | #endregion
77 |
78 | #region Methods
79 |
80 | ///
81 | /// Refreshes the internal FileSystemWatcher asynchronously
82 | ///
83 | ///
84 | public Task RefreshAsync(bool returnWhenRefreshed = true)
85 | {
86 | return Task.Factory.StartNew(()=>Refresh(returnWhenRefreshed));
87 | }
88 |
89 | ///
90 | /// Refreshes the internal FileSystemWatcher
91 | ///
92 | public void Refresh()
93 | {
94 | // when using this synchronous method, the call should make sure to return only when the watcher has been refreshed.
95 | Refresh(returnWhenRefreshed: true);
96 | }
97 |
98 | ///
99 | /// Refreshes the internal FileSystemWatcher
100 | ///
101 | /// In case another thread is alreayd refreshing, determines wether the thread should return before the refreshing thread finishes or not.
102 | private void Refresh(bool returnWhenRefreshed)
103 | {
104 | // Making sure another thread isn't already refreshing:
105 | if (!Monitor.TryEnter(_refreshLock))
106 | {
107 | // if another thread IS already refreshing - wait for it to finish then return
108 | if (returnWhenRefreshed)
109 | {
110 | WaitForRefresh();
111 | }
112 | return;
113 | }
114 | IsRefreshing = true;
115 |
116 | // 1. unsubscribe from old watcher's events.
117 | UnsubscribeFromInternalWatcherEvents();
118 |
119 | // 2a. Keeping the current internal "EnableRaisingEvents" value
120 | bool currentEnableRaisingEvents = InternalWatcher.EnableRaisingEvents;
121 | // 2b. Turning off EnableRaisingEvents to avoid "locking" the watched folder
122 | InternalWatcher.EnableRaisingEvents = false;
123 |
124 | // 3. Get a new watcher
125 | IFileSystemWatcher newInternalWatcher = GetReplacementWatcher();
126 | newInternalWatcher.EnableRaisingEvents = currentEnableRaisingEvents;
127 |
128 | // 4. Disposing of the old watcher
129 | InternalWatcher.Dispose();
130 |
131 | // 5. Place new watcher in the Internal watcher property
132 | // This also registers to the watcher's events
133 | InternalWatcher = newInternalWatcher;
134 |
135 | // Change state back to "not refreshing"
136 | IsRefreshing = false;
137 | // Notify any waiting threads that the refresh is done
138 | foreach (var waitingThreadEvent in _waitingThreadsEvents.Values)
139 | {
140 | waitingThreadEvent.Set();
141 | }
142 | _waitingThreadsEvents.Clear();
143 | Monitor.Exit(_refreshLock);
144 |
145 | // Notify listeners about the refresh.
146 | Refreshed?.Invoke(this, new EventArgs());
147 | }
148 |
149 | ///
150 | /// Gets a replacement for the InternalWatcher
151 | ///
152 | /// A new IFileSystemWatcher of the same type as the InternalWatcher
153 | private IFileSystemWatcher GetReplacementWatcher()
154 | {
155 | IFileSystemWatcher newInternalWatcher = null;
156 | // Swallowing any exceptions that might occure when trying to get a clone of the current watcher
157 | CancellationToken cToken = _refreshTokenSource.Token;
158 | Policy.Handle()
159 | .RetryForever((ex, con) => Thread.Sleep(RefreshAttempInterval))
160 | .Execute(() =>
161 | {
162 | // If the refreshment is cancelled, place a fake as the new watcher and return.
163 | if (cToken.IsCancellationRequested)
164 | {
165 | newInternalWatcher = new FileSystemFakeWatcher();
166 | return; //Exits polly's 'Execute' method.
167 | }
168 |
169 | newInternalWatcher = (IFileSystemWatcher) InternalWatcher.Clone();
170 | // setting EnableRaisingEvents to true is where exceptions may raise so
171 | // I'm giving this clone a "test drive" before returning it to the Refresh method
172 | newInternalWatcher.EnableRaisingEvents = true;
173 | newInternalWatcher.EnableRaisingEvents = false;
174 | });
175 |
176 | return newInternalWatcher;
177 | }
178 |
179 | ///
180 | /// Blocks the thread while a refresh is in progress
181 | ///
182 | public void WaitForRefresh()
183 | {
184 | // Create a reset event and adds it to the waiting threads events list
185 | ManualResetEventSlim refreshEvent = new ManualResetEventSlim(false);
186 | _waitingThreadsEvents[Thread.CurrentThread] = refreshEvent;
187 | refreshEvent.Wait();
188 | }
189 |
190 | ///
191 | /// Blocks the thread while a refresh is in progress
192 | ///
193 | /// Maximum amount of time, in ms, to wait for the refresh to finish.
194 | /// True if the refresh finished in time, false if the wait timed out.
195 | public bool WaitForRefresh(int timeout)
196 | {
197 | // Create a reset event and adds it to the waiting threads events list
198 | ManualResetEventSlim refreshEvent = new ManualResetEventSlim(false);
199 | _waitingThreadsEvents[Thread.CurrentThread] = refreshEvent;
200 |
201 | var refreshed = refreshEvent.Wait(timeout); // waiting for the refresh
202 |
203 | if (!refreshed) // = wait timed out
204 | {
205 | // remove the event from the list
206 | _waitingThreadsEvents.TryRemove(Thread.CurrentThread, out refreshEvent);
207 | }
208 | return refreshed;
209 | }
210 |
211 | #endregion
212 |
213 | #region IDisposeable Methods
214 |
215 | ~FileSystemRefreshableWatcher()
216 | {
217 | Dispose(false);
218 | }
219 |
220 | public new void Dispose()
221 | {
222 | Dispose(true);
223 | GC.SuppressFinalize(this);
224 | }
225 |
226 | private void Dispose(bool disposing)
227 | {
228 | // If the refresher is currently refreshing, cancel the refresh and wait for the refreshing thread to exit
229 | if (IsRefreshing)
230 | {
231 | _refreshTokenSource.Cancel();
232 | WaitForRefresh();
233 | }
234 |
235 | if (disposing)
236 | {
237 | base.Dispose();
238 | }
239 | }
240 |
241 | #endregion
242 |
243 | #region ICloneable Methods
244 |
245 | public override object Clone()
246 | {
247 | var clonedInternalWatcher = (IFileSystemWatcher) InternalWatcher.Clone();
248 | return new FileSystemRefreshableWatcher(clonedInternalWatcher) { RefreshAttempInterval = this.RefreshAttempInterval };
249 | }
250 |
251 | #endregion
252 | }
253 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Wrappers/FileSystemWatcherAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace FileSystemWatcherAlts.Wrappers
5 | {
6 | ///
7 | /// Adapts a FileSystemWatcher to make it fit the IFileSystemWatcher interface
8 | ///
9 | public class FileSystemWatcherAdapter : IFileSystemWatcher
10 | {
11 | #region Fields
12 |
13 | private FileSystemWatcher _watcher;
14 |
15 | #endregion
16 |
17 | #region Constructors
18 |
19 | public FileSystemWatcherAdapter(FileSystemWatcher watcherToWrap)
20 | {
21 | _watcher = watcherToWrap;
22 | SubscribeToPrivateWatcherEvents();
23 | }
24 | public FileSystemWatcherAdapter() : this(new FileSystemWatcher())
25 | {
26 | }
27 |
28 | public FileSystemWatcherAdapter(string path) : this(new FileSystemWatcher(path))
29 | {
30 | }
31 |
32 | public FileSystemWatcherAdapter(string path, string filter) : this(new FileSystemWatcher(path,filter))
33 | {
34 | }
35 |
36 | #endregion
37 |
38 | #region Events
39 |
40 | public event FileSystemEventHandler Changed;
41 | public event FileSystemEventHandler Created;
42 | public event FileSystemEventHandler Deleted;
43 | public event ErrorEventHandler Error;
44 | public event RenamedEventHandler Renamed;
45 |
46 | #endregion
47 |
48 | #region Proprties
49 | protected FileSystemWatcher InternalWatcher
50 | {
51 | get { return _watcher; }
52 | set
53 | {
54 | UnsubscribeFromPrivateWatcherEvents();
55 | _watcher = value;
56 | SubscribeToPrivateWatcherEvents();
57 | }
58 | }
59 |
60 | public bool EnableRaisingEvents
61 | {
62 | get
63 | {
64 | return InternalWatcher.EnableRaisingEvents;
65 | }
66 | set
67 | {
68 | InternalWatcher.EnableRaisingEvents = value;
69 | }
70 | }
71 |
72 | public string Filter
73 | {
74 | get
75 | {
76 | return InternalWatcher.Filter;
77 | }
78 | set
79 | {
80 | InternalWatcher.Filter = value;
81 | }
82 | }
83 |
84 | public bool IncludeSubdirectories
85 | {
86 | get
87 | {
88 | return InternalWatcher.IncludeSubdirectories;
89 | }
90 | set
91 | {
92 | InternalWatcher.IncludeSubdirectories = value;
93 | }
94 | }
95 |
96 | public int InternalBufferSize
97 | {
98 | get
99 | {
100 | return InternalWatcher.InternalBufferSize;
101 | }
102 | set
103 | {
104 | InternalWatcher.InternalBufferSize = value;
105 | }
106 | }
107 |
108 | public NotifyFilters NotifyFilter
109 | {
110 | get
111 | {
112 | return InternalWatcher.NotifyFilter;
113 | }
114 | set
115 | {
116 | InternalWatcher.NotifyFilter = value;
117 | }
118 | }
119 |
120 | public string Path
121 | {
122 | get
123 | {
124 | return InternalWatcher.Path;
125 | }
126 | set
127 | {
128 | InternalWatcher.Path = value;
129 | }
130 | }
131 |
132 | #endregion
133 |
134 | #region Watcher Refreshing
135 |
136 | protected void SubscribeToPrivateWatcherEvents()
137 | {
138 | if (InternalWatcher == null) return;
139 |
140 | InternalWatcher.Created += OnCreated;
141 | InternalWatcher.Changed += OnChanged;
142 | InternalWatcher.Deleted += OnDeleted;
143 | InternalWatcher.Error += OnError;
144 | InternalWatcher.Renamed += OnRenamed;
145 | }
146 |
147 | protected void UnsubscribeFromPrivateWatcherEvents()
148 | {
149 | if (InternalWatcher == null) return;
150 |
151 | InternalWatcher.Created -= OnCreated;
152 | InternalWatcher.Changed -= OnChanged;
153 | InternalWatcher.Deleted -= OnDeleted;
154 | InternalWatcher.Error -= OnError;
155 | InternalWatcher.Renamed -= OnRenamed;
156 | }
157 |
158 | protected void OnChanged(object sender, FileSystemEventArgs fileSystemEventArgs) => Changed?.Invoke(sender, fileSystemEventArgs);
159 | protected void OnCreated(object sender, FileSystemEventArgs fileSystemEventArgs) => Created?.Invoke(sender, fileSystemEventArgs);
160 | protected void OnDeleted(object sender, FileSystemEventArgs fileSystemEventArgs) => Deleted?.Invoke(sender, fileSystemEventArgs);
161 | protected void OnError(object sender, ErrorEventArgs fileSystemErrorArgs) => Error?.Invoke(sender, fileSystemErrorArgs);
162 | protected void OnRenamed(object sender, RenamedEventArgs fileSystemEventArgs) => Renamed?.Invoke(sender, fileSystemEventArgs);
163 |
164 | #endregion
165 |
166 | #region Mmethods
167 |
168 | public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType)
169 | {
170 | return InternalWatcher.WaitForChanged(changeType);
171 | }
172 |
173 | public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, int timeout)
174 | {
175 | return InternalWatcher.WaitForChanged(changeType, timeout);
176 | }
177 |
178 | #endregion
179 |
180 | #region IDisposeable Methods
181 |
182 | ~FileSystemWatcherAdapter()
183 | {
184 | Dispose(false);
185 | }
186 |
187 | public void Dispose()
188 | {
189 | Dispose(true);
190 | GC.SuppressFinalize(this);
191 | }
192 |
193 | private void Dispose(bool disposing)
194 | {
195 | UnsubscribeFromPrivateWatcherEvents();
196 |
197 | if (disposing)
198 | {
199 | _watcher.Dispose();
200 | }
201 | }
202 | #endregion
203 |
204 | #region ICloneable Methods
205 |
206 | public object Clone()
207 | {
208 | FileSystemWatcher clonedEncapsWatcher = new FileSystemWatcher()
209 | {
210 | NotifyFilter = InternalWatcher.NotifyFilter,
211 | Path = InternalWatcher.Path,
212 | IncludeSubdirectories = InternalWatcher.IncludeSubdirectories,
213 | InternalBufferSize = InternalWatcher.InternalBufferSize,
214 | Filter = InternalWatcher.Filter,
215 | EnableRaisingEvents = InternalWatcher.EnableRaisingEvents
216 | };
217 | return new FileSystemWatcherAdapter(clonedEncapsWatcher);
218 | }
219 |
220 | #endregion
221 |
222 | }
223 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/Wrappers/FileSystemWatcherWrapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace FileSystemWatcherAlts.Wrappers
5 | {
6 | ///
7 | /// An abstract wrapper for an IFilesystemWatcher
8 | ///
9 | public abstract class FileSystemWatcherWrapper : IFileSystemWatcher
10 | {
11 |
12 | #region Fields
13 |
14 | private IFileSystemWatcher _internalWatcher;
15 |
16 | #endregion
17 |
18 | #region Events
19 |
20 | public virtual event FileSystemEventHandler Changed;
21 | public virtual event FileSystemEventHandler Created;
22 | public virtual event FileSystemEventHandler Deleted;
23 | public virtual event ErrorEventHandler Error;
24 | public virtual event RenamedEventHandler Renamed;
25 |
26 | #endregion
27 |
28 | #region Proprties
29 |
30 | protected IFileSystemWatcher InternalWatcher
31 | {
32 | get { return _internalWatcher; }
33 | set
34 | {
35 | UnsubscribeFromInternalWatcherEvents();
36 | _internalWatcher = value;
37 | SubscribeToPrivateWatcherEvents();
38 | }
39 | }
40 |
41 | public virtual bool EnableRaisingEvents
42 | {
43 | get
44 | {
45 | return InternalWatcher.EnableRaisingEvents;
46 | }
47 | set
48 | {
49 | InternalWatcher.EnableRaisingEvents = value;
50 | }
51 | }
52 |
53 | public virtual string Filter
54 | {
55 | get
56 | {
57 | return InternalWatcher.Filter;
58 | }
59 | set
60 | {
61 | InternalWatcher.Filter = value;
62 | }
63 | }
64 |
65 | public virtual bool IncludeSubdirectories
66 | {
67 | get
68 | {
69 | return InternalWatcher.IncludeSubdirectories;
70 | }
71 | set
72 | {
73 | InternalWatcher.IncludeSubdirectories = value;
74 | }
75 | }
76 |
77 | public virtual int InternalBufferSize
78 | {
79 | get
80 | {
81 | return InternalWatcher.InternalBufferSize;
82 | }
83 | set
84 | {
85 | InternalWatcher.InternalBufferSize = value;
86 | }
87 | }
88 |
89 | public virtual NotifyFilters NotifyFilter
90 | {
91 | get
92 | {
93 | return InternalWatcher.NotifyFilter;
94 | }
95 | set
96 | {
97 | InternalWatcher.NotifyFilter = value;
98 | }
99 | }
100 |
101 | public virtual string Path
102 | {
103 | get
104 | {
105 | return InternalWatcher.Path;
106 | }
107 | set
108 | {
109 | InternalWatcher.Path = value;
110 | }
111 | }
112 |
113 | #endregion
114 |
115 | #region Constructors
116 |
117 | protected FileSystemWatcherWrapper(IFileSystemWatcher watcher)
118 | {
119 | InternalWatcher = watcher;
120 | }
121 | protected FileSystemWatcherWrapper(FileSystemWatcher watcher) : this(new FileSystemWatcherAdapter(watcher))
122 | {
123 | }
124 | protected FileSystemWatcherWrapper() : this(new FileSystemWatcherAdapter())
125 | {
126 | }
127 | protected FileSystemWatcherWrapper(string path) : this(new FileSystemWatcherAdapter(path))
128 | {
129 | }
130 | protected FileSystemWatcherWrapper(string path, string filter) : this(new FileSystemWatcherAdapter(path, filter))
131 | {
132 | }
133 |
134 | #endregion
135 |
136 | #region Events related Methods
137 |
138 | // Subscribe/Unsubscribe from wrapped watcher's events
139 | protected virtual void SubscribeToPrivateWatcherEvents()
140 | {
141 | if (InternalWatcher == null) return;
142 |
143 | InternalWatcher.Created += OnCreated;
144 | InternalWatcher.Changed += OnChanged;
145 | InternalWatcher.Deleted += OnDeleted;
146 | InternalWatcher.Error += OnError;
147 | InternalWatcher.Renamed += OnRenamed;
148 | }
149 | protected virtual void UnsubscribeFromInternalWatcherEvents()
150 | {
151 | if (InternalWatcher == null) return;
152 |
153 | InternalWatcher.Created -= OnCreated;
154 | InternalWatcher.Changed -= OnChanged;
155 | InternalWatcher.Deleted -= OnDeleted;
156 | InternalWatcher.Error -= OnError;
157 | InternalWatcher.Renamed -= OnRenamed;
158 | }
159 |
160 | // Events Invokers
161 | protected virtual void OnChanged(object sender, FileSystemEventArgs fileSystemEventArgs) => Changed?.Invoke(sender, fileSystemEventArgs);
162 | protected virtual void OnCreated(object sender, FileSystemEventArgs fileSystemEventArgs) => Created?.Invoke(sender, fileSystemEventArgs);
163 | protected virtual void OnDeleted(object sender, FileSystemEventArgs fileSystemEventArgs) => Deleted?.Invoke(sender, fileSystemEventArgs);
164 | protected virtual void OnError(object sender, ErrorEventArgs fileSystemErrorArgs) => Error?.Invoke(sender, fileSystemErrorArgs);
165 | protected virtual void OnRenamed(object sender, RenamedEventArgs fileSystemEventArgs) => Renamed?.Invoke(sender, fileSystemEventArgs);
166 |
167 | #endregion
168 |
169 | #region Override methods
170 |
171 | public virtual WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType)
172 | {
173 | return InternalWatcher.WaitForChanged(changeType);
174 | }
175 |
176 | public virtual WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, int timeout)
177 | {
178 | return InternalWatcher.WaitForChanged(changeType, timeout);
179 | }
180 |
181 | #endregion
182 |
183 | #region IDisposable Methods
184 |
185 | ~FileSystemWatcherWrapper()
186 | {
187 | Dispose(false);
188 | }
189 |
190 | public void Dispose()
191 | {
192 | Dispose(true);
193 | GC.SuppressFinalize(this);
194 | }
195 |
196 | private void Dispose(bool disposing)
197 | {
198 | UnsubscribeFromInternalWatcherEvents();
199 |
200 | if (disposing)
201 | {
202 | InternalWatcher.Dispose();
203 | }
204 | }
205 |
206 | #endregion
207 |
208 | #region ICloneable Methods
209 |
210 | public abstract object Clone();
211 |
212 | #endregion
213 |
214 | }
215 | }
--------------------------------------------------------------------------------
/FileSystemWatcherAlts/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Shai S
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ⚠️ This project is not maintained.
2 | I suggest seeking other solutions like this one:
3 | https://petermeinl.wordpress.com/2015/05/18/tamed-filesystemwatcher/
4 |
5 | 
6 | # FileSystemWatcherAlts[](https://ci.appveyor.com/project/Wootness/filesystemwatcheralts)
7 |
8 | ###### _Resolving your files watching trust issues since 2015._
9 |
10 |
11 | ## What Is This?
12 | A collection of alternatives to the System.IO.FileSystemWatcher class.
13 |
14 | ## What's Wrong With System.IO.FileSystemWatcher?
15 | As you can see with a quick google search - FilesystemWatcher is far from perfect.
16 | In fact, it is problematic enough that Microsoft gave it an "Error" event so you can react when it encounters a problem.
17 | To put it in simple words, there are 2 main issues with it:
18 |
19 | 1. It misses file changes when under heavy load, rendering it unreliable.
20 | 2. It stops working under certain circumstances.
21 |
22 | ## Show Me What You Got
23 | The alternatives offered are:
24 |
25 | 1. `FileSystemPoller` - Periodicly polls for file system changes.
26 | 2. `FileSystemRefreshableWatcher` - A watcher wrapper. Allows the user to restart a broken watcher.
27 | 3. `FileSystemAutoRefreshingWatcher` - A watcher wrapper. *Automatically* restarts a watcher if it breaks.
28 | 4. `FileSystemOverseer` - A watcher wrapper. Automatically restarts a watcher if it breaks and uses a backup poller for increased reliability.
29 |
30 | The table over here shows you the upsides and downsides of FileSystemWatcher and my alternatives.
31 | Choose the one that fits your requirements.
32 |
33 | ## Usage
34 |
35 | All alternatives in this library implements an interface called **"IFileSystemWatcher"**
36 | It defines methods and events corresponding to the ones in System.IO.FileSystemWatcher.
37 | If your project is already utilizing FileSytemWatcher you can simply change this:
38 |
39 | ```C#
40 | FileSystemWatcher sysMonitor = new FileSystemWatcher(@"C:\");
41 | ```
42 |
43 | To any of those:
44 |
45 | ```C#
46 | IFileSystemWatcher sysMonitor = new FileSystemRefreshableWatcher(@"C:\");
47 | IFileSystemWatcher sysMonitor = new FileSystemAutoRefreshingWatcher(@"C:\");
48 | IFileSystemWatcher sysMonitor = new FileSystemPoller(pollingInterval: 500,path: @"C:\");
49 | IFileSystemWatcher sysMonitor = new FileSystemOverseer(pollingInterval: 500, path: @"C:\");
50 | ```
51 |
52 | Then use Created/Deleted/Renamed/Changed events as you would with FileSystemWatcher.
53 |
54 |
55 | ## Thanks
56 | Icon: Binoculars designed by Gregor Crešnar from The Noun Project
57 |
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/Polly.2.2.3.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theXappy/FileSystemWatcherAlts/6e228ed78367cb7aca7e4aa90debb9d737584441/packages/Polly.2.2.3/Polly.2.2.3.nupkg
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/net35/Polly.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theXappy/FileSystemWatcherAlts/6e228ed78367cb7aca7e4aa90debb9d737584441/packages/Polly.2.2.3/lib/net35/Polly.dll
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/net35/Polly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Polly
5 |
6 |
7 |
8 |
9 | Fluent API for defining a Circuit Breaker .
10 |
11 |
12 |
13 |
14 | Builds a that will function like a Circuit Breaker.
15 | The circuit will break after
16 | exceptions that are handled by this policy are raised. The circuit will stay
17 | broken for the . Any attempt to execute this policy
18 | while the circuit is broken, will immediately throw a containing the exception
19 | that broke the cicuit.
20 |
21 | If the first action after the break duration period results in an exception, the circuit will break
22 | again for another , otherwise it will reset.
23 |
24 |
25 | The policy builder.
26 | The number of exceptions that are allowed before opening the circuit.
27 | The duration the circuit will stay open before resetting.
28 | The policy instance.
29 | (see "Release It!" by Michael T. Nygard fi)
30 | exceptionsAllowedBeforeBreaking;Value must be greater than zero.
31 |
32 |
33 |
34 | Exception thrown when a circuit is broken.
35 |
36 |
37 |
38 |
39 | Initializes a new instance of the class.
40 |
41 |
42 |
43 |
44 | Initializes a new instance of the class.
45 |
46 | The message that describes the error.
47 |
48 |
49 |
50 | Initializes a new instance of the class.
51 |
52 | The message.
53 | The inner.
54 |
55 |
56 |
57 | Initializes a new instance of the class.
58 |
59 | The that holds the serialized object data about the exception being thrown.
60 | The that contains contextual information about the source or destination.
61 |
62 |
63 |
64 | A readonly dictionary of string key / object value pairs
65 |
66 |
67 |
68 | http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=29
69 |
70 | Provides the base class for a generic read-only dictionary.
71 |
72 |
73 | The type of keys in the dictionary.
74 |
75 |
76 | The type of values in the dictionary.
77 |
78 |
79 |
80 | An instance of the ReadOnlyDictionary generic class is
81 | always read-only. A dictionary that is read-only is simply a
82 | dictionary with a wrapper that prevents modifying the
83 | dictionary; therefore, if changes are made to the underlying
84 | dictionary, the read-only dictionary reflects those changes.
85 | See for a modifiable version of
86 | this class.
87 |
88 |
89 | Notes to Implementers This base class is provided to
90 | make it easier for implementers to create a generic read-only
91 | custom dictionary. Implementers are encouraged to extend this
92 | base class instead of creating their own.
93 |
94 |
95 |
96 |
97 |
98 | Initializes a new instance of the
99 | class that wraps
100 | the supplied .
101 |
102 | The
103 | that will be wrapped.
104 |
105 | Thrown when the dictionary is null.
106 |
107 |
108 |
109 | This method is not supported by the
110 | .
111 |
112 | The object to use as the key of the element to add.
113 |
114 | The object to use as the value of the element to add.
115 |
116 |
117 | Determines whether the
118 | contains the specified key.
119 |
120 | True if the contains
121 | an element with the specified key; otherwise, false.
122 |
123 | The key to locate in the
124 | .
125 |
126 | Thrown when the key is null.
127 |
128 |
129 |
130 |
131 | This method is not supported by the .
132 |
133 | The key of the element to remove.
134 |
135 | True if the element is successfully removed; otherwise, false.
136 |
137 |
138 |
139 |
140 | Gets the value associated with the specified key.
141 |
142 | The key of the value to get.
143 | When this method returns, contains the value
144 | associated with the specified key, if the key is found;
145 | otherwise, the default value for the type of the value parameter.
146 | This parameter is passed uninitialized.
147 |
148 | true if the contains
149 | an element with the specified key; otherwise, false.
150 |
151 |
152 |
153 | This method is not supported by the
154 | .
155 |
156 | The object to add to the .
157 |
158 |
159 |
160 | This method is not supported by the
161 | .
162 |
163 |
164 |
165 | Determines whether the contains a
166 | specific value.
167 |
168 |
169 | The object to locate in the .
170 |
171 |
172 | true if item is found in the ICollection;
173 | otherwise, false.
174 |
175 |
176 |
177 |
178 | Copies the elements of the ICollection to an Array, starting at a
179 | particular Array index.
180 |
181 | The one-dimensional Array that is the
182 | destination of the elements copied from ICollection.
183 | The Array must have zero-based indexing.
184 |
185 |
186 | The zero-based index in array at which copying begins.
187 |
188 |
189 |
190 | This method is not supported by the
191 | .
192 |
193 | The object to remove from the ICollection.
194 |
195 | Will never return a value.
196 |
197 |
198 |
199 | Returns an enumerator that iterates through the collection.
200 |
201 |
202 | A IEnumerator that can be used to iterate through the collection.
203 |
204 |
205 |
206 |
207 | Returns an enumerator that iterates through a collection.
208 |
209 |
210 | An IEnumerator that can be used to iterate through the collection.
211 |
212 |
213 |
214 |
215 | For a description of this member, see .
216 |
217 |
218 | The one-dimensional Array that is the destination of the elements copied from
219 | ICollection. The Array must have zero-based indexing.
220 |
221 |
222 | The zero-based index in Array at which copying begins.
223 |
224 |
225 |
226 |
227 | Gets the number of key/value pairs contained in the
228 | .
229 |
230 | The number of key/value pairs.
231 | The number of key/value pairs contained in the
232 | .
233 |
234 |
235 | Gets a collection containing the keys in the
236 | .
237 | A
238 | containing the keys.
239 | A
240 |
241 | containing the keys in the
242 | .
243 |
244 |
245 |
246 |
247 | Gets a collection containing the values of the
248 | .
249 |
250 | The collection of values.
251 |
252 |
253 | Gets a value indicating whether the dictionary is read-only.
254 | This value will always be true.
255 |
256 |
257 |
258 | Gets a value indicating whether access to the dictionary
259 | is synchronized (thread safe).
260 |
261 |
262 |
263 |
264 | Gets an object that can be used to synchronize access to dictionary.
265 |
266 |
267 |
268 |
269 | Gets or sets the value associated with the specified key.
270 |
271 |
272 | The value associated with the specified key. If the specified key
273 | is not found, a get operation throws a
274 | ,
275 | and a set operation creates a new element with the specified key.
276 |
277 | The key of the value to get or set.
278 |
279 | Thrown when the key is null.
280 |
281 |
282 | The property is retrieved and key does not exist in the collection.
283 |
284 |
285 |
286 |
287 | Transient exception handling policies that can be applied to delegates.
288 | These policies can be called with arbitrary context data.
289 |
290 |
291 |
292 |
293 | Executes the specified action within the policy.
294 |
295 | The action to perform.
296 | Arbitrary data that is passed to the exception policy.
297 | contextData
298 |
299 |
300 |
301 | Executes the specified action within the policy.
302 |
303 | The action to perform.
304 |
305 |
306 |
307 | Executes the specified action within the policy and returns the Result.
308 |
309 | The type of the Result.
310 | The action to perform.
311 | Arbitrary data that is passed to the exception policy.
312 |
313 | The value returned by the action
314 |
315 | contextData
316 |
317 |
318 |
319 | Executes the specified action within the policy and returns the Result.
320 |
321 | The type of the Result.
322 | The action to perform.
323 |
324 | The value returned by the action
325 |
326 |
327 |
328 |
329 | Fluent API for chaining exceptions that will be handled by a .
330 |
331 |
332 |
333 |
334 | Specifies the type of exception that this policy can handle.
335 |
336 | The type of the exception to handle.
337 | The current builder to chain off.
338 | The PolicyBuilder instance.
339 |
340 |
341 |
342 | Specifies the type of exception that this policy can handle with addition filters on this exception type.
343 |
344 | The type of the exception.
345 | The current builder to chain off.
346 | The exception predicate to filter the type of exception this policy can handle.
347 | The PolicyBuilder instance.
348 |
349 |
350 |
351 | Transient exception handling policies that can
352 | be applied to delegates
353 |
354 |
355 |
356 |
357 | Executes the specified action within the policy.
358 |
359 | The action to perform.
360 |
361 |
362 |
363 | Executes the specified action within the policy and returns the captured result
364 |
365 | The action to perform.
366 | The captured result
367 |
368 |
369 |
370 | Executes the specified action within the policy and returns the result.
371 |
372 | The type of the result.
373 | The action to perform.
374 | The value returned by the action
375 |
376 |
377 |
378 | Executes the specified action within the policy and returns the captured result
379 |
380 | The action to perform.
381 | The captured result
382 |
383 |
384 |
385 | Specifies the type of exception that this policy can handle.
386 |
387 | The type of the exception to handle.
388 | The PolicyBuilder instance.
389 |
390 |
391 |
392 | Specifies the type of exception that this policy can handle with addition filters on this exception type.
393 |
394 | The type of the exception.
395 | The exception predicate to filter the type of exception this policy can handle.
396 | The PolicyBuilder instance.
397 |
398 |
399 |
400 | Builder class that holds the list of current exception predicates.
401 |
402 |
403 |
404 |
405 | Returns a that represents this instance.
406 |
407 |
408 | A that represents this instance.
409 |
410 |
411 |
412 |
413 | Determines whether the specified is equal to this instance.
414 |
415 | The to compare with this instance.
416 |
417 | true if the specified is equal to this instance; otherwise, false.
418 |
419 |
420 |
421 |
422 | Returns a hash code for this instance.
423 |
424 |
425 | A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
426 |
427 |
428 |
429 |
430 | Gets the of the current instance.
431 |
432 |
433 | The instance that represents the exact runtime type of the current instance.
434 |
435 |
436 |
437 |
438 | The captured result of executing a policy
439 |
440 |
441 |
442 |
443 | The outcome of executing the policy
444 |
445 |
446 |
447 |
448 | The final exception captured. Will be null if policy executed successfully
449 |
450 |
451 |
452 |
453 | The exception type of the final exception captured. Will be null if policy executed successfully
454 |
455 |
456 |
457 |
458 | The captured result of executing a policy
459 |
460 |
461 |
462 |
463 | The outcome of executing the policy
464 |
465 |
466 |
467 |
468 | The final exception captured. Will be null if policy executed successfully
469 |
470 |
471 |
472 |
473 | The exception type of the final exception captured. Will be null if policy executed successfully
474 |
475 |
476 |
477 |
478 | The result of executing the policy. Will be default(TResult) is the policy failed
479 |
480 |
481 |
482 |
483 | Represents the outcome of executing a policy
484 |
485 |
486 |
487 |
488 | Indicates that the policy ultimately executed successfully
489 |
490 |
491 |
492 |
493 | Indicates that the policy ultimately failed
494 |
495 |
496 |
497 |
498 | Represents the type of exception resulting from a failed policy
499 |
500 |
501 |
502 |
503 | An exception type that has been defined to be handled by this policy
504 |
505 |
506 |
507 |
508 | An exception type that has been not been defined to be handled by this policy
509 |
510 |
511 |
512 |
513 | Fluent API for defining a Retry .
514 |
515 |
516 |
517 |
518 | Builds a that will retry once.
519 |
520 | The policy builder.
521 | The policy instance.
522 |
523 |
524 |
525 | Builds a that will retry times.
526 |
527 | The policy builder.
528 | The retry count.
529 | The policy instance.
530 |
531 |
532 |
533 | Builds a that will retry once
534 | calling on retry with the raised exception and retry count.
535 |
536 | The policy builder.
537 | The action to call on each retry.
538 | The policy instance.
539 | retryCount;Value must be greater than zero.
540 | onRetry
541 |
542 |
543 |
544 | Builds a that will retry times
545 | calling on each retry with the raised exception and retry count.
546 |
547 | The policy builder.
548 | The retry count.
549 | The action to call on each retry.
550 | The policy instance.
551 | retryCount;Value must be greater than zero.
552 | onRetry
553 |
554 |
555 |
556 | Builds a that will retry once
557 | calling on retry with the raised exception, retry count and
558 | execution context.
559 |
560 | The policy builder.
561 | The action to call on each retry.
562 | The policy instance.
563 | retryCount;Value must be greater than zero.
564 | onRetry
565 |
566 |
567 |
568 | Builds a that will retry times
569 | calling on each retry with the raised exception, retry count and
570 | execution context.
571 |
572 | The policy builder.
573 | The retry count.
574 | The action to call on each retry.
575 | The policy instance.
576 | retryCount;Value must be greater than zero.
577 | onRetry
578 |
579 |
580 |
581 | Builds a that will retry indefinitely.
582 |
583 | The policy builder.
584 | The policy instance.
585 |
586 |
587 |
588 | Builds a that will retry indefinitely
589 | calling on each retry with the raised exception.
590 |
591 | The policy builder.
592 | The action to call on each retry.
593 | The policy instance.
594 | onRetry
595 |
596 |
597 |
598 | Builds a that will retry indefinitely
599 | calling on each retry with the raised exception and
600 | execution context.
601 |
602 | The policy builder.
603 | The action to call on each retry.
604 | The policy instance.
605 | onRetry
606 |
607 |
608 |
609 | Builds a that will wait and retry times.
610 | On each retry, the duration to wait is calculated by calling with
611 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
612 |
613 | The policy builder.
614 | The retry count.
615 | The function that provides the duration to wait for for a particular retry attempt.
616 | The policy instance.
617 |
618 |
619 |
620 | Builds a that will wait and retry times
621 | calling on each retry with the raised exception and the current sleep duration.
622 | On each retry, the duration to wait is calculated by calling with
623 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
624 |
625 | The policy builder.
626 | The retry count.
627 | The function that provides the duration to wait for for a particular retry attempt.
628 | The action to call on each retry.
629 | The policy instance.
630 | retryCount;Value must be greater than zero.
631 |
632 | timeSpanProvider
633 | or
634 | onRetry
635 |
636 |
637 |
638 |
639 | Builds a that will wait and retry times
640 | calling on each retry with the raised exception, current sleep duration and
641 | execution context.
642 | On each retry, the duration to wait is calculated by calling with
643 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
644 |
645 | The policy builder.
646 | The retry count.
647 | The function that provides the duration to wait for for a particular retry attempt.
648 | The action to call on each retry.
649 | The policy instance.
650 | retryCount;Value must be greater than zero.
651 |
652 | timeSpanProvider
653 | or
654 | onRetry
655 |
656 |
657 |
658 |
659 | Builds a that will wait and retry as many times as there are provided
660 | On each retry, the duration to wait is the current item.
661 |
662 | The policy builder.
663 | The sleep durations to wait for on each retry.
664 | The policy instance.
665 |
666 |
667 |
668 | Builds a that will wait and retry as many times as there are provided
669 | calling on each retry with the raised exception and the current sleep duration.
670 | On each retry, the duration to wait is the current item.
671 |
672 | The policy builder.
673 | The sleep durations to wait for on each retry.
674 | The action to call on each retry.
675 | The policy instance.
676 |
677 | sleepDurations
678 | or
679 | onRetry
680 |
681 |
682 |
683 |
684 | Builds a that will wait and retry as many times as there are provided
685 | calling on each retry with the raised exception, current sleep duration and
686 | execution context.
687 | On each retry, the duration to wait is the current item.
688 |
689 | The policy builder.
690 | The sleep durations to wait for on each retry.
691 | The action to call on each retry.
692 | The policy instance.
693 |
694 | sleepDurations
695 | or
696 | onRetry
697 |
698 |
699 |
700 |
701 | Time related delegates used to improve testability of the code
702 |
703 |
704 |
705 |
706 | Allows the setting of a custom Thread.Sleep implementation for testing.
707 | By default this will be a call to
708 |
709 |
710 |
711 |
712 | Allows the setting of a custom DateTime.UtcNow implementation for testing.
713 | By default this will be a call to
714 |
715 |
716 |
717 |
718 | Resets the custom implementations to their defaults.
719 | Should be called during test teardowns.
720 |
721 |
722 |
723 |
724 |
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/net40/Polly.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theXappy/FileSystemWatcherAlts/6e228ed78367cb7aca7e4aa90debb9d737584441/packages/Polly.2.2.3/lib/net40/Polly.dll
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/net45/Polly.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theXappy/FileSystemWatcherAlts/6e228ed78367cb7aca7e4aa90debb9d737584441/packages/Polly.2.2.3/lib/net45/Polly.dll
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/net45/Polly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Polly
5 |
6 |
7 |
8 |
9 | Fluent API for defining a Circuit Breaker .
10 |
11 |
12 |
13 |
14 | Builds a that will function like a Circuit Breaker.
15 | The circuit will break after
16 | exceptions that are handled by this policy are raised. The circuit will stay
17 | broken for the . Any attempt to execute this policy
18 | while the circuit is broken, will immediately throw a containing the exception
19 | that broke the cicuit.
20 |
21 | If the first action after the break duration period results in an exception, the circuit will break
22 | again for another , otherwise it will reset.
23 |
24 |
25 | The policy builder.
26 | The number of exceptions that are allowed before opening the circuit.
27 | The duration the circuit will stay open before resetting.
28 | The policy instance.
29 | (see "Release It!" by Michael T. Nygard fi)
30 | exceptionsAllowedBeforeBreaking;Value must be greater than zero.
31 |
32 |
33 |
34 | Exception thrown when a circuit is broken.
35 |
36 |
37 |
38 |
39 | Initializes a new instance of the class.
40 |
41 |
42 |
43 |
44 | Initializes a new instance of the class.
45 |
46 | The message that describes the error.
47 |
48 |
49 |
50 | Initializes a new instance of the class.
51 |
52 | The message.
53 | The inner.
54 |
55 |
56 |
57 | Initializes a new instance of the class.
58 |
59 | The that holds the serialized object data about the exception being thrown.
60 | The that contains contextual information about the source or destination.
61 |
62 |
63 |
64 | Transient exception handling policies that can be applied to delegates.
65 | These policies can be called with arbitrary context data.
66 |
67 |
68 |
69 |
70 | Executes the specified action within the policy.
71 |
72 | The action to perform.
73 | Arbitrary data that is passed to the exception policy.
74 | contextData
75 |
76 |
77 |
78 | Executes the specified action within the policy.
79 |
80 | The action to perform.
81 |
82 |
83 |
84 | Executes the specified action within the policy and returns the Result.
85 |
86 | The type of the Result.
87 | The action to perform.
88 | Arbitrary data that is passed to the exception policy.
89 |
90 | The value returned by the action
91 |
92 | contextData
93 |
94 |
95 |
96 | Executes the specified action within the policy and returns the Result.
97 |
98 | The type of the Result.
99 | The action to perform.
100 |
101 | The value returned by the action
102 |
103 |
104 |
105 |
106 | Fluent API for chaining exceptions that will be handled by a .
107 |
108 |
109 |
110 |
111 | Specifies the type of exception that this policy can handle.
112 |
113 | The type of the exception to handle.
114 | The current builder to chain off.
115 | The PolicyBuilder instance.
116 |
117 |
118 |
119 | Specifies the type of exception that this policy can handle with addition filters on this exception type.
120 |
121 | The type of the exception.
122 | The current builder to chain off.
123 | The exception predicate to filter the type of exception this policy can handle.
124 | The PolicyBuilder instance.
125 |
126 |
127 |
128 | Transient exception handling policies that can
129 | be applied to delegates
130 |
131 |
132 |
133 |
134 | Executes the specified action within the policy.
135 |
136 | The action to perform.
137 |
138 |
139 |
140 | Executes the specified action within the policy and returns the captured result
141 |
142 | The action to perform.
143 | The captured result
144 |
145 |
146 |
147 | Executes the specified action within the policy and returns the result.
148 |
149 | The type of the result.
150 | The action to perform.
151 | The value returned by the action
152 |
153 |
154 |
155 | Executes the specified action within the policy and returns the captured result
156 |
157 | The action to perform.
158 | The captured result
159 |
160 |
161 |
162 | Specifies the type of exception that this policy can handle.
163 |
164 | The type of the exception to handle.
165 | The PolicyBuilder instance.
166 |
167 |
168 |
169 | Specifies the type of exception that this policy can handle with addition filters on this exception type.
170 |
171 | The type of the exception.
172 | The exception predicate to filter the type of exception this policy can handle.
173 | The PolicyBuilder instance.
174 |
175 |
176 |
177 | Executes the specified asynchronous action within the policy.
178 |
179 | The action to perform.
180 |
181 |
182 |
183 | Executes the specified asynchronous action within the policy and returns the captured result.
184 |
185 | The action to perform.
186 |
187 |
188 |
189 | Executes the specified asynchronous action within the policy and returns the result.
190 |
191 | The type of the result.
192 | The action to perform.
193 | The value returned by the action
194 |
195 |
196 |
197 | Executes the specified asynchronous action within the policy and returns the result.
198 |
199 | The type of the result.
200 | The action to perform.
201 | The value returned by the action
202 |
203 |
204 |
205 | Builder class that holds the list of current exception predicates.
206 |
207 |
208 |
209 |
210 | Returns a that represents this instance.
211 |
212 |
213 | A that represents this instance.
214 |
215 |
216 |
217 |
218 | Determines whether the specified is equal to this instance.
219 |
220 | The to compare with this instance.
221 |
222 | true if the specified is equal to this instance; otherwise, false.
223 |
224 |
225 |
226 |
227 | Returns a hash code for this instance.
228 |
229 |
230 | A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
231 |
232 |
233 |
234 |
235 | Gets the of the current instance.
236 |
237 |
238 | The instance that represents the exact runtime type of the current instance.
239 |
240 |
241 |
242 |
243 | The captured result of executing a policy
244 |
245 |
246 |
247 |
248 | The outcome of executing the policy
249 |
250 |
251 |
252 |
253 | The final exception captured. Will be null if policy executed successfully
254 |
255 |
256 |
257 |
258 | The exception type of the final exception captured. Will be null if policy executed successfully
259 |
260 |
261 |
262 |
263 | The captured result of executing a policy
264 |
265 |
266 |
267 |
268 | The outcome of executing the policy
269 |
270 |
271 |
272 |
273 | The final exception captured. Will be null if policy executed successfully
274 |
275 |
276 |
277 |
278 | The exception type of the final exception captured. Will be null if policy executed successfully
279 |
280 |
281 |
282 |
283 | The result of executing the policy. Will be default(TResult) is the policy failed
284 |
285 |
286 |
287 |
288 | Represents the outcome of executing a policy
289 |
290 |
291 |
292 |
293 | Indicates that the policy ultimately executed successfully
294 |
295 |
296 |
297 |
298 | Indicates that the policy ultimately failed
299 |
300 |
301 |
302 |
303 | Represents the type of exception resulting from a failed policy
304 |
305 |
306 |
307 |
308 | An exception type that has been defined to be handled by this policy
309 |
310 |
311 |
312 |
313 | An exception type that has been not been defined to be handled by this policy
314 |
315 |
316 |
317 |
318 | Fluent API for defining a Retry .
319 |
320 |
321 | Fluent API for defining a Retry .
322 |
323 |
324 |
325 |
326 | Builds a that will retry once.
327 |
328 | The policy builder.
329 | The policy instance.
330 |
331 |
332 |
333 | Builds a that will retry times.
334 |
335 | The policy builder.
336 | The retry count.
337 | The policy instance.
338 |
339 |
340 |
341 | Builds a that will retry once
342 | calling on retry with the raised exception and retry count.
343 |
344 | The policy builder.
345 | The action to call on each retry.
346 | The policy instance.
347 | retryCount;Value must be greater than zero.
348 | onRetry
349 |
350 |
351 |
352 | Builds a that will retry times
353 | calling on each retry with the raised exception and retry count.
354 |
355 | The policy builder.
356 | The retry count.
357 | The action to call on each retry.
358 | The policy instance.
359 | retryCount;Value must be greater than zero.
360 | onRetry
361 |
362 |
363 |
364 | Builds a that will retry once
365 | calling on retry with the raised exception, retry count and
366 | execution context.
367 |
368 | The policy builder.
369 | The action to call on each retry.
370 | The policy instance.
371 | retryCount;Value must be greater than zero.
372 | onRetry
373 |
374 |
375 |
376 | Builds a that will retry times
377 | calling on each retry with the raised exception, retry count and
378 | execution context.
379 |
380 | The policy builder.
381 | The retry count.
382 | The action to call on each retry.
383 | The policy instance.
384 | retryCount;Value must be greater than zero.
385 | onRetry
386 |
387 |
388 |
389 | Builds a that will retry indefinitely.
390 |
391 | The policy builder.
392 | The policy instance.
393 |
394 |
395 |
396 | Builds a that will retry indefinitely
397 | calling on each retry with the raised exception.
398 |
399 | The policy builder.
400 | The action to call on each retry.
401 | The policy instance.
402 | onRetry
403 |
404 |
405 |
406 | Builds a that will retry indefinitely
407 | calling on each retry with the raised exception and
408 | execution context.
409 |
410 | The policy builder.
411 | The action to call on each retry.
412 | The policy instance.
413 | onRetry
414 |
415 |
416 |
417 | Builds a that will wait and retry times.
418 | On each retry, the duration to wait is calculated by calling with
419 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
420 |
421 | The policy builder.
422 | The retry count.
423 | The function that provides the duration to wait for for a particular retry attempt.
424 | The policy instance.
425 |
426 |
427 |
428 | Builds a that will wait and retry times
429 | calling on each retry with the raised exception and the current sleep duration.
430 | On each retry, the duration to wait is calculated by calling with
431 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
432 |
433 | The policy builder.
434 | The retry count.
435 | The function that provides the duration to wait for for a particular retry attempt.
436 | The action to call on each retry.
437 | The policy instance.
438 | retryCount;Value must be greater than zero.
439 |
440 | timeSpanProvider
441 | or
442 | onRetry
443 |
444 |
445 |
446 |
447 | Builds a that will wait and retry times
448 | calling on each retry with the raised exception, current sleep duration and
449 | execution context.
450 | On each retry, the duration to wait is calculated by calling with
451 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
452 |
453 | The policy builder.
454 | The retry count.
455 | The function that provides the duration to wait for for a particular retry attempt.
456 | The action to call on each retry.
457 | The policy instance.
458 | retryCount;Value must be greater than zero.
459 |
460 | timeSpanProvider
461 | or
462 | onRetry
463 |
464 |
465 |
466 |
467 | Builds a that will wait and retry as many times as there are provided
468 | On each retry, the duration to wait is the current item.
469 |
470 | The policy builder.
471 | The sleep durations to wait for on each retry.
472 | The policy instance.
473 |
474 |
475 |
476 | Builds a that will wait and retry as many times as there are provided
477 | calling on each retry with the raised exception and the current sleep duration.
478 | On each retry, the duration to wait is the current item.
479 |
480 | The policy builder.
481 | The sleep durations to wait for on each retry.
482 | The action to call on each retry.
483 | The policy instance.
484 |
485 | sleepDurations
486 | or
487 | onRetry
488 |
489 |
490 |
491 |
492 | Builds a that will wait and retry as many times as there are provided
493 | calling on each retry with the raised exception, current sleep duration and
494 | execution context.
495 | On each retry, the duration to wait is the current item.
496 |
497 | The policy builder.
498 | The sleep durations to wait for on each retry.
499 | The action to call on each retry.
500 | The policy instance.
501 |
502 | sleepDurations
503 | or
504 | onRetry
505 |
506 |
507 |
508 |
509 | Builds a that will retry once.
510 |
511 | The policy builder.
512 | The policy instance.
513 |
514 |
515 |
516 | Builds a that will retry times.
517 |
518 | The policy builder.
519 | The retry count.
520 | The policy instance.
521 |
522 |
523 |
524 | Builds a that will retry once
525 | calling on retry with the raised exception and retry count.
526 |
527 | The policy builder.
528 | The action to call on each retry.
529 | The policy instance.
530 | retryCount;Value must be greater than zero.
531 | onRetry
532 |
533 |
534 |
535 | Builds a that will retry times
536 | calling on each retry with the raised exception and retry count.
537 |
538 | The policy builder.
539 | The retry count.
540 | The action to call on each retry.
541 | The policy instance.
542 | retryCount;Value must be greater than zero.
543 | onRetry
544 |
545 |
546 |
547 | Builds a that will retry indefinitely.
548 |
549 | The policy builder.
550 | The policy instance.
551 |
552 |
553 |
554 | Builds a that will retry indefinitely
555 | calling on each retry with the raised exception.
556 |
557 | The policy builder.
558 | The action to call on each retry.
559 | The policy instance.
560 | onRetry
561 |
562 |
563 |
564 | Builds a that will wait and retry as many times as there are provided
565 |
566 | On each retry, the duration to wait is the current item.
567 |
568 | The policy builder.
569 | The sleep durations to wait for on each retry.
570 | The policy instance.
571 |
572 |
573 |
574 | Builds a that will wait and retry times.
575 | On each retry, the duration to wait is calculated by calling with
576 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
577 |
578 | The policy builder.
579 | The retry count.
580 | The function that provides the duration to wait for for a particular retry attempt.
581 | The policy instance.
582 |
583 |
584 |
585 | Builds a that will wait and retry times
586 | calling on each retry with the raised exception and the current sleep duration.
587 | On each retry, the duration to wait is calculated by calling with
588 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
589 |
590 | The policy builder.
591 | The retry count.
592 | The function that provides the duration to wait for for a particular retry attempt.
593 | The action to call on each retry.
594 | The policy instance.
595 | retryCount;Value must be greater than zero.
596 |
597 | timeSpanProvider
598 | or
599 | onRetry
600 |
601 |
602 |
603 |
604 | Builds a that will wait and retry as many times as there are provided
605 |
606 | calling on each retry with the raised exception and the current sleep duration.
607 | On each retry, the duration to wait is the current item.
608 |
609 | The policy builder.
610 | The sleep durations to wait for on each retry.
611 | The action to call on each retry.
612 | The policy instance.
613 |
614 | sleepDurations
615 | or
616 | onRetry
617 |
618 |
619 |
620 |
621 | Time related delegates used to improve testability of the code
622 |
623 |
624 |
625 |
626 | Allows the setting of a custom Thread.Sleep implementation for testing.
627 | By default this will be a call to
628 |
629 |
630 |
631 |
632 | Allows the setting of a custom DateTime.UtcNow implementation for testing.
633 | By default this will be a call to
634 |
635 |
636 |
637 |
638 | Resets the custom implementations to their defaults.
639 | Should be called during test teardowns.
640 |
641 |
642 |
643 |
644 | Fluent API for defining a Circuit Breaker .
645 |
646 |
647 |
648 |
649 | Builds a that will function like a Circuit Breaker.
650 | The circuit will break after
651 | exceptions that are handled by this policy are raised. The circuit will stay
652 | broken for the . Any attempt to execute this policy
653 | while the circuit is broken, will immediately throw a containing the exception
654 | that broke the cicuit.
655 |
656 | If the first action after the break duration period results in an exception, the circuit will break
657 | again for another , otherwise it will reset.
658 |
659 |
660 | The policy builder.
661 | The number of exceptions that are allowed before opening the circuit.
662 | The duration the circuit will stay open before resetting.
663 | The policy instance.
664 | (see "Release It!" by Michael T. Nygard fi)
665 | exceptionsAllowedBeforeBreaking;Value must be greater than zero.
666 |
667 |
668 |
669 | A readonly dictionary of string key / object value pairs
670 |
671 |
672 |
673 |
674 |
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Polly.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theXappy/FileSystemWatcherAlts/6e228ed78367cb7aca7e4aa90debb9d737584441/packages/Polly.2.2.3/lib/portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Polly.dll
--------------------------------------------------------------------------------
/packages/Polly.2.2.3/lib/portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1/Polly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Polly
5 |
6 |
7 |
8 |
9 | Fluent API for defining a Circuit Breaker .
10 |
11 |
12 |
13 |
14 | Builds a that will function like a Circuit Breaker.
15 | The circuit will break after
16 | exceptions that are handled by this policy are raised. The circuit will stay
17 | broken for the . Any attempt to execute this policy
18 | while the circuit is broken, will immediately throw a containing the exception
19 | that broke the cicuit.
20 |
21 | If the first action after the break duration period results in an exception, the circuit will break
22 | again for another , otherwise it will reset.
23 |
24 |
25 | The policy builder.
26 | The number of exceptions that are allowed before opening the circuit.
27 | The duration the circuit will stay open before resetting.
28 | The policy instance.
29 | (see "Release It!" by Michael T. Nygard fi)
30 | exceptionsAllowedBeforeBreaking;Value must be greater than zero.
31 |
32 |
33 |
34 | Exception thrown when a circuit is broken.
35 |
36 |
37 |
38 |
39 | Initializes a new instance of the class.
40 |
41 |
42 |
43 |
44 | Initializes a new instance of the class.
45 |
46 | The message that describes the error.
47 |
48 |
49 |
50 | Initializes a new instance of the class.
51 |
52 | The message.
53 | The inner.
54 |
55 |
56 |
57 | Transient exception handling policies that can be applied to delegates.
58 | These policies can be called with arbitrary context data.
59 |
60 |
61 |
62 |
63 | Executes the specified action within the policy.
64 |
65 | The action to perform.
66 | Arbitrary data that is passed to the exception policy.
67 | contextData
68 |
69 |
70 |
71 | Executes the specified action within the policy.
72 |
73 | The action to perform.
74 |
75 |
76 |
77 | Executes the specified action within the policy and returns the Result.
78 |
79 | The type of the Result.
80 | The action to perform.
81 | Arbitrary data that is passed to the exception policy.
82 |
83 | The value returned by the action
84 |
85 | contextData
86 |
87 |
88 |
89 | Executes the specified action within the policy and returns the Result.
90 |
91 | The type of the Result.
92 | The action to perform.
93 |
94 | The value returned by the action
95 |
96 |
97 |
98 |
99 | Fluent API for chaining exceptions that will be handled by a .
100 |
101 |
102 |
103 |
104 | Specifies the type of exception that this policy can handle.
105 |
106 | The type of the exception to handle.
107 | The current builder to chain off.
108 | The PolicyBuilder instance.
109 |
110 |
111 |
112 | Specifies the type of exception that this policy can handle with addition filters on this exception type.
113 |
114 | The type of the exception.
115 | The current builder to chain off.
116 | The exception predicate to filter the type of exception this policy can handle.
117 | The PolicyBuilder instance.
118 |
119 |
120 |
121 | Transient exception handling policies that can
122 | be applied to delegates
123 |
124 |
125 |
126 |
127 | Executes the specified action within the policy.
128 |
129 | The action to perform.
130 |
131 |
132 |
133 | Executes the specified action within the policy and returns the captured result
134 |
135 | The action to perform.
136 | The captured result
137 |
138 |
139 |
140 | Executes the specified action within the policy and returns the result.
141 |
142 | The type of the result.
143 | The action to perform.
144 | The value returned by the action
145 |
146 |
147 |
148 | Executes the specified action within the policy and returns the captured result
149 |
150 | The action to perform.
151 | The captured result
152 |
153 |
154 |
155 | Specifies the type of exception that this policy can handle.
156 |
157 | The type of the exception to handle.
158 | The PolicyBuilder instance.
159 |
160 |
161 |
162 | Specifies the type of exception that this policy can handle with addition filters on this exception type.
163 |
164 | The type of the exception.
165 | The exception predicate to filter the type of exception this policy can handle.
166 | The PolicyBuilder instance.
167 |
168 |
169 |
170 | Executes the specified asynchronous action within the policy.
171 |
172 | The action to perform.
173 |
174 |
175 |
176 | Executes the specified asynchronous action within the policy and returns the captured result.
177 |
178 | The action to perform.
179 |
180 |
181 |
182 | Executes the specified asynchronous action within the policy and returns the result.
183 |
184 | The type of the result.
185 | The action to perform.
186 | The value returned by the action
187 |
188 |
189 |
190 | Executes the specified asynchronous action within the policy and returns the result.
191 |
192 | The type of the result.
193 | The action to perform.
194 | The value returned by the action
195 |
196 |
197 |
198 | Builder class that holds the list of current exception predicates.
199 |
200 |
201 |
202 |
203 | Returns a that represents this instance.
204 |
205 |
206 | A that represents this instance.
207 |
208 |
209 |
210 |
211 | Determines whether the specified is equal to this instance.
212 |
213 | The to compare with this instance.
214 |
215 | true if the specified is equal to this instance; otherwise, false.
216 |
217 |
218 |
219 |
220 | Returns a hash code for this instance.
221 |
222 |
223 | A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
224 |
225 |
226 |
227 |
228 | Gets the of the current instance.
229 |
230 |
231 | The instance that represents the exact runtime type of the current instance.
232 |
233 |
234 |
235 |
236 | The captured result of executing a policy
237 |
238 |
239 |
240 |
241 | The outcome of executing the policy
242 |
243 |
244 |
245 |
246 | The final exception captured. Will be null if policy executed successfully
247 |
248 |
249 |
250 |
251 | The exception type of the final exception captured. Will be null if policy executed successfully
252 |
253 |
254 |
255 |
256 | The captured result of executing a policy
257 |
258 |
259 |
260 |
261 | The outcome of executing the policy
262 |
263 |
264 |
265 |
266 | The final exception captured. Will be null if policy executed successfully
267 |
268 |
269 |
270 |
271 | The exception type of the final exception captured. Will be null if policy executed successfully
272 |
273 |
274 |
275 |
276 | The result of executing the policy. Will be default(TResult) is the policy failed
277 |
278 |
279 |
280 |
281 | Represents the outcome of executing a policy
282 |
283 |
284 |
285 |
286 | Indicates that the policy ultimately executed successfully
287 |
288 |
289 |
290 |
291 | Indicates that the policy ultimately failed
292 |
293 |
294 |
295 |
296 | Represents the type of exception resulting from a failed policy
297 |
298 |
299 |
300 |
301 | An exception type that has been defined to be handled by this policy
302 |
303 |
304 |
305 |
306 | An exception type that has been not been defined to be handled by this policy
307 |
308 |
309 |
310 |
311 | Fluent API for defining a Retry .
312 |
313 |
314 | Fluent API for defining a Retry .
315 |
316 |
317 |
318 |
319 | Builds a that will retry once.
320 |
321 | The policy builder.
322 | The policy instance.
323 |
324 |
325 |
326 | Builds a that will retry times.
327 |
328 | The policy builder.
329 | The retry count.
330 | The policy instance.
331 |
332 |
333 |
334 | Builds a that will retry once
335 | calling on retry with the raised exception and retry count.
336 |
337 | The policy builder.
338 | The action to call on each retry.
339 | The policy instance.
340 | retryCount;Value must be greater than zero.
341 | onRetry
342 |
343 |
344 |
345 | Builds a that will retry times
346 | calling on each retry with the raised exception and retry count.
347 |
348 | The policy builder.
349 | The retry count.
350 | The action to call on each retry.
351 | The policy instance.
352 | retryCount;Value must be greater than zero.
353 | onRetry
354 |
355 |
356 |
357 | Builds a that will retry once
358 | calling on retry with the raised exception, retry count and
359 | execution context.
360 |
361 | The policy builder.
362 | The action to call on each retry.
363 | The policy instance.
364 | retryCount;Value must be greater than zero.
365 | onRetry
366 |
367 |
368 |
369 | Builds a that will retry times
370 | calling on each retry with the raised exception, retry count and
371 | execution context.
372 |
373 | The policy builder.
374 | The retry count.
375 | The action to call on each retry.
376 | The policy instance.
377 | retryCount;Value must be greater than zero.
378 | onRetry
379 |
380 |
381 |
382 | Builds a that will retry indefinitely.
383 |
384 | The policy builder.
385 | The policy instance.
386 |
387 |
388 |
389 | Builds a that will retry indefinitely
390 | calling on each retry with the raised exception.
391 |
392 | The policy builder.
393 | The action to call on each retry.
394 | The policy instance.
395 | onRetry
396 |
397 |
398 |
399 | Builds a that will retry indefinitely
400 | calling on each retry with the raised exception and
401 | execution context.
402 |
403 | The policy builder.
404 | The action to call on each retry.
405 | The policy instance.
406 | onRetry
407 |
408 |
409 |
410 | Builds a that will wait and retry times.
411 | On each retry, the duration to wait is calculated by calling with
412 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
413 |
414 | The policy builder.
415 | The retry count.
416 | The function that provides the duration to wait for for a particular retry attempt.
417 | The policy instance.
418 |
419 |
420 |
421 | Builds a that will wait and retry times
422 | calling on each retry with the raised exception and the current sleep duration.
423 | On each retry, the duration to wait is calculated by calling with
424 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
425 |
426 | The policy builder.
427 | The retry count.
428 | The function that provides the duration to wait for for a particular retry attempt.
429 | The action to call on each retry.
430 | The policy instance.
431 | retryCount;Value must be greater than zero.
432 |
433 | timeSpanProvider
434 | or
435 | onRetry
436 |
437 |
438 |
439 |
440 | Builds a that will wait and retry times
441 | calling on each retry with the raised exception, current sleep duration and
442 | execution context.
443 | On each retry, the duration to wait is calculated by calling with
444 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
445 |
446 | The policy builder.
447 | The retry count.
448 | The function that provides the duration to wait for for a particular retry attempt.
449 | The action to call on each retry.
450 | The policy instance.
451 | retryCount;Value must be greater than zero.
452 |
453 | timeSpanProvider
454 | or
455 | onRetry
456 |
457 |
458 |
459 |
460 | Builds a that will wait and retry as many times as there are provided
461 | On each retry, the duration to wait is the current item.
462 |
463 | The policy builder.
464 | The sleep durations to wait for on each retry.
465 | The policy instance.
466 |
467 |
468 |
469 | Builds a that will wait and retry as many times as there are provided
470 | calling on each retry with the raised exception and the current sleep duration.
471 | On each retry, the duration to wait is the current item.
472 |
473 | The policy builder.
474 | The sleep durations to wait for on each retry.
475 | The action to call on each retry.
476 | The policy instance.
477 |
478 | sleepDurations
479 | or
480 | onRetry
481 |
482 |
483 |
484 |
485 | Builds a that will wait and retry as many times as there are provided
486 | calling on each retry with the raised exception, current sleep duration and
487 | execution context.
488 | On each retry, the duration to wait is the current item.
489 |
490 | The policy builder.
491 | The sleep durations to wait for on each retry.
492 | The action to call on each retry.
493 | The policy instance.
494 |
495 | sleepDurations
496 | or
497 | onRetry
498 |
499 |
500 |
501 |
502 | Builds a that will retry once.
503 |
504 | The policy builder.
505 | The policy instance.
506 |
507 |
508 |
509 | Builds a that will retry times.
510 |
511 | The policy builder.
512 | The retry count.
513 | The policy instance.
514 |
515 |
516 |
517 | Builds a that will retry once
518 | calling on retry with the raised exception and retry count.
519 |
520 | The policy builder.
521 | The action to call on each retry.
522 | The policy instance.
523 | retryCount;Value must be greater than zero.
524 | onRetry
525 |
526 |
527 |
528 | Builds a that will retry times
529 | calling on each retry with the raised exception and retry count.
530 |
531 | The policy builder.
532 | The retry count.
533 | The action to call on each retry.
534 | The policy instance.
535 | retryCount;Value must be greater than zero.
536 | onRetry
537 |
538 |
539 |
540 | Builds a that will retry indefinitely.
541 |
542 | The policy builder.
543 | The policy instance.
544 |
545 |
546 |
547 | Builds a that will retry indefinitely
548 | calling on each retry with the raised exception.
549 |
550 | The policy builder.
551 | The action to call on each retry.
552 | The policy instance.
553 | onRetry
554 |
555 |
556 |
557 | Builds a that will wait and retry as many times as there are provided
558 |
559 | On each retry, the duration to wait is the current item.
560 |
561 | The policy builder.
562 | The sleep durations to wait for on each retry.
563 | The policy instance.
564 |
565 |
566 |
567 | Builds a that will wait and retry times.
568 | On each retry, the duration to wait is calculated by calling with
569 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
570 |
571 | The policy builder.
572 | The retry count.
573 | The function that provides the duration to wait for for a particular retry attempt.
574 | The policy instance.
575 |
576 |
577 |
578 | Builds a that will wait and retry times
579 | calling on each retry with the raised exception and the current sleep duration.
580 | On each retry, the duration to wait is calculated by calling with
581 | the current retry attempt allowing an exponentially increasing wait time (exponential backoff).
582 |
583 | The policy builder.
584 | The retry count.
585 | The function that provides the duration to wait for for a particular retry attempt.
586 | The action to call on each retry.
587 | The policy instance.
588 | retryCount;Value must be greater than zero.
589 |
590 | timeSpanProvider
591 | or
592 | onRetry
593 |
594 |
595 |
596 |
597 | Builds a that will wait and retry as many times as there are provided
598 |
599 | calling on each retry with the raised exception and the current sleep duration.
600 | On each retry, the duration to wait is the current item.
601 |
602 | The policy builder.
603 | The sleep durations to wait for on each retry.
604 | The action to call on each retry.
605 | The policy instance.
606 |
607 | sleepDurations
608 | or
609 | onRetry
610 |
611 |
612 |
613 |
614 | Time related delegates used to improve testability of the code
615 |
616 |
617 |
618 |
619 | Allows the setting of a custom Thread.Sleep implementation for testing.
620 | By default this will be a call to
621 |
622 |
623 |
624 |
625 | Allows the setting of a custom DateTime.UtcNow implementation for testing.
626 | By default this will be a call to
627 |
628 |
629 |
630 |
631 | Resets the custom implementations to their defaults.
632 | Should be called during test teardowns.
633 |
634 |
635 |
636 |
637 | A readonly dictionary of string key / object value pairs
638 |
639 |
640 |
641 |
642 | Fluent API for defining a Circuit Breaker .
643 |
644 |
645 |
646 |
647 | Builds a that will function like a Circuit Breaker.
648 | The circuit will break after
649 | exceptions that are handled by this policy are raised. The circuit will stay
650 | broken for the . Any attempt to execute this policy
651 | while the circuit is broken, will immediately throw a containing the exception
652 | that broke the cicuit.
653 |
654 | If the first action after the break duration period results in an exception, the circuit will break
655 | again for another , otherwise it will reset.
656 |
657 |
658 | The policy builder.
659 | The number of exceptions that are allowed before opening the circuit.
660 | The duration the circuit will stay open before resetting.
661 | The policy instance.
662 | (see "Release It!" by Michael T. Nygard fi)
663 | exceptionsAllowedBeforeBreaking;Value must be greater than zero.
664 |
665 |
666 |
667 |
--------------------------------------------------------------------------------