diff --git a/CrispyWaffle.sln.DotSettings b/CrispyWaffle.sln.DotSettings
new file mode 100644
index 00000000..3c536788
--- /dev/null
+++ b/CrispyWaffle.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ 3
\ No newline at end of file
diff --git a/Src/CrispyWaffle/Extensions/ConversionExtensions.cs b/Src/CrispyWaffle/Extensions/ConversionExtensions.cs
index 425c2a58..74019c6d 100644
--- a/Src/CrispyWaffle/Extensions/ConversionExtensions.cs
+++ b/Src/CrispyWaffle/Extensions/ConversionExtensions.cs
@@ -94,12 +94,15 @@ public static DateTime ToDateTime(this string input)
}
}
+
+
///
/// Tries to convert string to date time.
///
/// The input string a valid DateTime format.
/// The DateTime value.
/// True if success, false otherwise
+ // ReSharper disable once MethodTooLong
public static bool TryToDateTime(this string input, out DateTime value)
{
value = DateTime.MinValue;
@@ -110,30 +113,39 @@ public static bool TryToDateTime(this string input, out DateTime value)
{
case "agora":
case "now":
+
value = DateTime.Now;
+
return true;
+
case "hoje":
case "today":
+
value = DateTime.Today;
+
return true;
+
case "ontem":
case "yesterday":
+
value = DateTime.Today.AddDays(-1);
+
return true;
+
case "amanhã":
case "amanha":
case "tomorrow":
+
value = DateTime.Today.AddDays(1);
+
return true;
+
default:
+
if (DateTime.TryParse(input, out value))
return true;
- return input.Length == 10 &&
- DateTime.TryParseExact(input,
- @"dd/MM/yyyy",
- CultureInfo.InvariantCulture,
- DateTimeStyles.None,
- out value);
+
+ return input.Length == 10 && DateTime.TryParseExact(input, @"dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out value);
}
}
@@ -146,7 +158,9 @@ public static int ToInt32(this string input)
{
if (string.IsNullOrWhiteSpace(input))
return 0;
+
var success = int.TryParse(input, NumberStyles.Number, StringExtensions.Culture, out var result);
+
return success ? result : 0;
}
@@ -159,7 +173,9 @@ public static long ToInt64(this string input)
{
if (string.IsNullOrWhiteSpace(input))
return 0;
+
var success = long.TryParse(input, NumberStyles.Number, StringExtensions.Culture, out var result);
+
return success ? result : 0;
}
@@ -172,6 +188,7 @@ public static decimal ToDecimal(this string input)
{
if (string.IsNullOrWhiteSpace(input))
return 0M;
+
return decimal.TryParse(input, NumberStyles.Number, StringExtensions.Culture, out var result)
? result
: 0M;
@@ -232,8 +249,10 @@ public static DateTime FromUnixTimeStamp(this int epochTime)
public static PhoneNumber ParseBrazilianPhoneNumber(this string number)
{
var result = new PhoneNumber(0, 0, 0);
+
if (number.TryParseBrazilianPhoneNumber(ref result))
return result;
+
throw new InvalidTelephoneNumberException(number.RemoveNonNumeric());
}
@@ -262,11 +281,16 @@ public static bool TryParseBrazilianPhoneNumber(this string number, ref PhoneNum
(dirtyLength == 11 || dirtyLength == 12)
? dirty.Substring(1, 2)
: dirty.Substring(0, 2);
+
var hasNineDigits = dirty.Substring(dirtyLength - 9, 1)
.Equals(@"9", StringExtensions.Comparison);
+
var allowedDigits = hasNineDigits ? 9 : 8;
+
var telephoneNumber = dirty.Substring(dirtyLength - allowedDigits, allowedDigits);
+
result = new PhoneNumber(55, prefix.ToInt32(), telephoneNumber.ToInt64());
+
return true;
}
@@ -297,6 +321,7 @@ public static string ToIdentString(this XmlDocument document)
{
if (document == null)
return null;
+
var builder = new StringBuilder();
var settings = new XmlWriterSettings
@@ -350,6 +375,16 @@ public static int ToModule10(this string input)
return digit;
}
+ ///
+ /// The ordinal suffix
+ ///
+ private static readonly Dictionary OrdinalSuffix = new Dictionary
+ {
+ {1,"st"},
+ {2,"nd"},
+ {3,"rd"}
+ };
+
///
/// To the ordinal.
///
@@ -359,20 +394,18 @@ public static string ToOrdinal(this long number)
{
if (number < 0)
return number.ToString();
+
var rem = number % 100;
+
if (rem >= 11 && rem <= 13)
return $"{number}th";
- switch (number % 10)
- {
- case 1:
- return $"{number}st";
- case 2:
- return $"{number}nd";
- case 3:
- return $"{number}rd";
- default:
- return $"{number}th";
- }
+
+
+ var key = (int)number % 10;
+ if (OrdinalSuffix.ContainsKey(key))
+ return $"{number}{OrdinalSuffix[key]}";
+
+ return $"{number}th";
}
///
@@ -427,27 +460,45 @@ public static T DeepClone(this T instance, bool useNonPublic = true)
var arguments = new List
/// The type.
/// Boolean.
+ // ReSharper disable once CognitiveComplexity
public static bool IsNumericType(this Type type)
{
while (true)
diff --git a/Src/CrispyWaffle/Log/Adapters/EventLogAdapter.cs b/Src/CrispyWaffle/Log/Adapters/EventLogAdapter.cs
new file mode 100644
index 00000000..f5cf40f6
--- /dev/null
+++ b/Src/CrispyWaffle/Log/Adapters/EventLogAdapter.cs
@@ -0,0 +1,383 @@
+using CrispyWaffle.Log.Providers;
+using CrispyWaffle.Serialization;
+using System;
+using System.Diagnostics;
+
+namespace CrispyWaffle.Log.Adapters
+{
+ ///
+ /// Class EventLogAdapter. This class cannot be inherited.
+ /// Implements the
+ ///
+ ///
+ public sealed class EventLogAdapter : ILogAdapter
+ {
+ #region Consts
+
+ ///
+ /// The application log name
+ ///
+ private const string ApplicationLogName = "Application";
+ ///
+ /// The maximum payload length chars
+ ///
+ const int MaximumPayloadLengthChars = 31839;
+
+ ///
+ /// The maximum source name length chars
+ ///
+ const int MaximumSourceNameLengthChars = 212;
+
+ ///
+ /// The source moved event identifier
+ ///
+ const int SourceMovedEventId = 3;
+
+ ///
+ /// The event identifier provider
+ ///
+ readonly IEventIdProvider _eventIdProvider;
+
+ ///
+ /// The log
+ ///
+ readonly EventLog _log;
+
+ ///
+ /// The level
+ ///
+ private LogLevel _level;
+
+ #endregion
+
+ #region ~Ctors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ /// Name of the log.
+ /// Name of the machine.
+ /// if set to true [manage event source].
+ /// The event identifier provider.
+ /// source
+ /// eventIdProvider
+ public EventLogAdapter(string source, string logName, string machineName, bool manageEventSource,
+ IEventIdProvider eventIdProvider)
+ {
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ if (source.Length > MaximumSourceNameLengthChars)
+ {
+ source = source.Substring(0, MaximumSourceNameLengthChars);
+ }
+
+ source = source.Replace("<", "_");
+ source = source.Replace(">", "_");
+
+ _eventIdProvider = eventIdProvider ?? throw new ArgumentNullException(nameof(eventIdProvider));
+
+ _log = new EventLog(string.IsNullOrWhiteSpace(logName) ? ApplicationLogName : logName, machineName);
+
+ if (manageEventSource)
+ {
+ ConfigureSource(_log, source);
+ }
+ else
+ {
+ _log.Source = source;
+ }
+ }
+
+ #endregion
+
+ #region Private methods
+
+ ///
+ /// Configures the source.
+ ///
+ /// The log.
+ /// The source.
+ private static void ConfigureSource(EventLog log, string source)
+ {
+ var sourceData = new EventSourceCreationData(source, log.Log) { MachineName = log.MachineName };
+
+ string oldLogName = null;
+
+ if (EventLog.SourceExists(source, log.MachineName))
+ {
+ var existingLogWithSourceName = EventLog.LogNameFromSourceName(source, log.MachineName);
+
+ if (!string.IsNullOrWhiteSpace(existingLogWithSourceName) &&
+ !log.Log.Equals(existingLogWithSourceName, StringComparison.OrdinalIgnoreCase))
+ {
+ // Remove the source from the previous log so we can associate it with the current log name
+ EventLog.DeleteEventSource(source, log.MachineName);
+ oldLogName = existingLogWithSourceName;
+ }
+ }
+ else
+ {
+ EventLog.CreateEventSource(sourceData);
+ }
+
+ NotifyLogSourceChange(log, source, oldLogName);
+
+ log.Source = source;
+ }
+
+ ///
+ /// Notifies the log source change.
+ ///
+ /// The log.
+ /// The source.
+ /// Old name of the log.
+ private static void NotifyLogSourceChange(EventLog log, string source, string oldLogName)
+ {
+ if (oldLogName != null)
+ {
+ var metaSource = $"serilog-{log.Log}";
+ if (!EventLog.SourceExists(metaSource, log.MachineName))
+ EventLog.CreateEventSource(new EventSourceCreationData(metaSource, log.Log)
+ {
+ MachineName = log.MachineName
+ });
+
+ log.Source = metaSource;
+ log.WriteEntry(
+ $"Event source {source} was previously registered in log {oldLogName}. " +
+ $"The source has been registered with this log, {log.Log}, however a computer restart may be required " +
+ $"before event logs will appear in {log.Log} with source {source}. Until then, messages may be logged to {oldLogName}.",
+ EventLogEntryType.Warning,
+ SourceMovedEventId);
+ }
+ }
+
+
+ ///
+ /// Levels the type of to event log entry.
+ ///
+ /// The level.
+ /// EventLogEntryType.
+ private static EventLogEntryType LevelToEventLogEntryType(LogLevel level)
+ {
+ switch (level)
+ {
+ case LogLevel.DEBUG:
+ case LogLevel.TRACE:
+ return EventLogEntryType.Information;
+
+ case LogLevel.WARNING:
+ return EventLogEntryType.Warning;
+
+ case LogLevel.ERROR:
+ case LogLevel.FATAL:
+ return EventLogEntryType.Error;
+
+ default:
+ return EventLogEntryType.Information;
+ }
+ }
+
+ ///
+ /// Writes the internal.
+ ///
+ /// The level.
+ /// The message.
+ private void WriteInternal(LogLevel level, string message)
+ {
+ if (!_level.HasFlag(level))
+ return;
+
+ var type = LevelToEventLogEntryType(level);
+
+ if (message.Length > MaximumPayloadLengthChars)
+ {
+ message = message.Substring(0, MaximumPayloadLengthChars);
+ }
+
+ _log.WriteEntry(message, type, _eventIdProvider.ComputeEventId(message));
+ }
+
+ ///
+ /// Writes the internal.
+ ///
+ /// The level.
+ /// The exception.
+ private void WriteInternal(LogLevel level, Exception exception)
+ {
+
+ if (!_level.HasFlag(level))
+ return;
+
+ var type = LevelToEventLogEntryType(level);
+
+ var message = GetMessageFromException(exception);
+
+ if (message.Length > MaximumPayloadLengthChars)
+ {
+ message = message.Substring(0, MaximumPayloadLengthChars);
+ }
+
+ _log.WriteEntry(message, type, _eventIdProvider.ComputeEventId(message));
+
+ }
+
+ ///
+ /// Gets the message from exception.
+ ///
+ /// The exception.
+ /// System.String.
+ private static string GetMessageFromException(Exception exception)
+ {
+ var message = string.Empty;
+
+ do
+ {
+ message += exception.Message;
+ message += "\r\n";
+ message += exception.StackTrace;
+ message += "\r\n";
+
+ exception = exception.InnerException;
+ } while (exception != null);
+
+ return message;
+ }
+
+ #endregion
+
+ #region Implementation of IDisposable
+
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ public void Dispose()
+ { }
+
+ #endregion
+
+ #region Implementation of ILogAdapter
+
+ ///
+ /// Change the LogLevel of Log Adapter instance.
+ ///
+ /// The new level of the instance
+ public void SetLevel(LogLevel level)
+ {
+ _level = level;
+ }
+
+ ///
+ /// Save the serializer version of in the file ,
+ /// using default SerializerFormat, or a custom serializer format provided by .
+ ///
+ /// The type of the parameter
+ /// The object/instance of a class to be serialized and saved in a disk file
+ /// The file name to be persisted to disk with the content
+ /// Whatever or not to use a custom Serializer adapter different that one that is default for type
+ /// Requires LogLevel.DEBUG flag
+ public void Debug(T content, string identifier, SerializerFormat customFormat = SerializerFormat.NONE)
+ where T : class
+ {
+ if (!_level.HasFlag(LogLevel.DEBUG))
+ return;
+
+ var contentAsString = customFormat == SerializerFormat.NONE
+ ? content.GetSerializer()
+ : content.GetCustomSerializer(customFormat);
+
+ Debug((string)contentAsString, identifier);
+ }
+
+ ///
+ /// Save the string into a file with name
+ ///
+ /// The file content
+ /// The file name
+ /// Requires LogLevel.DEBUG flag
+ public void Debug(string content, string fileName)
+ {
+ WriteInternal(LogLevel.DEBUG, $"{fileName}: {content}");
+ }
+
+ ///
+ /// Logs a message as DEBUG level
+ ///
+ /// The message to be logged.
+ /// Requires LogLevel.DEBUG flag.
+ public void Debug(string message)
+ {
+ WriteInternal(LogLevel.DEBUG, message);
+ }
+
+ ///
+ /// Logs the exception with trace level.
+ ///
+ /// The exception.
+ public void Trace(Exception exception)
+ {
+ WriteInternal(LogLevel.TRACE, exception);
+ }
+
+ ///
+ /// Logs the message with trace level and shows exception details.
+ ///
+ /// The message to be logged.
+ /// The exception.
+ public void Trace(string message, Exception exception)
+ {
+ WriteInternal(LogLevel.TRACE, message);
+ WriteInternal(LogLevel.TRACE, exception);
+ }
+
+ ///
+ /// Logs a message as TRACE level
+ ///
+ /// The message to be logged.
+ /// Requires LogLevel.TRACE flag.
+ public void Trace(string message)
+ {
+ WriteInternal(LogLevel.TRACE, message);
+ }
+
+ ///
+ /// Logs a message as INFO level
+ ///
+ /// The message to be logged.
+ /// Requires LogLevel.INFO flag.
+ public void Info(string message)
+ {
+ WriteInternal(LogLevel.INFO, message);
+ }
+
+ ///
+ /// Logs a message as WARNING level.
+ ///
+ /// The message to be logged.
+ /// Requires LogLevel.WARNING flag.
+ public void Warning(string message)
+ {
+ WriteInternal(LogLevel.WARNING, message);
+ }
+
+ ///
+ /// Logs a message as ERROR level.
+ ///
+ /// The message to be logged.
+ /// Requires LogLevel.ERROR flag.
+ public void Error(string message)
+ {
+ WriteInternal(LogLevel.ERROR, message);
+ }
+
+ ///
+ /// Logs a message as FATAL level.
+ ///
+ /// The message.
+ public void Fatal(string message)
+ {
+ WriteInternal(LogLevel.FATAL, message);
+ }
+
+ #endregion
+ }
+}
diff --git a/Src/CrispyWaffle/Log/Providers/EventIdProvider.cs b/Src/CrispyWaffle/Log/Providers/EventIdProvider.cs
new file mode 100644
index 00000000..60d65592
--- /dev/null
+++ b/Src/CrispyWaffle/Log/Providers/EventIdProvider.cs
@@ -0,0 +1,56 @@
+using System;
+
+namespace CrispyWaffle.Log.Providers
+{
+ ///
+ /// Class EventIdProvider.
+ /// Implements the
+ ///
+ ///
+ public class EventIdProvider : IEventIdProvider
+ {
+ ///
+ /// Compute a 32-bit hash of the provided . The
+ /// resulting hash value can be uses as an event id in lieu of transmitting the
+ /// full template string.
+ ///
+ /// A message template.
+ /// A 32-bit hash of the template.
+ static int Compute(string message)
+ {
+ if (message == null) throw new ArgumentNullException(nameof(message));
+
+ // Jenkins one-at-a-time https://en.wikipedia.org/wiki/Jenkins_hash_function
+ unchecked
+ {
+ uint hash = 0;
+
+ foreach (var t in message)
+ {
+ hash += t;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ //even though the api is type int, eventID must be between 0 and 65535
+ //https://msdn.microsoft.com/en-us/library/d3159s0c(v=vs.110).aspx
+ return (ushort)hash;
+ }
+ }
+
+ #region Implementation of IEventIdProvider
+
+ ///
+ /// Computes the event identifier.
+ ///
+ /// The message.
+ /// System.UInt16.
+ public ushort ComputeEventId(string message) => (ushort)Compute(message);
+
+ #endregion
+ }
+}
diff --git a/Src/CrispyWaffle/Log/Providers/EventLogProvider.cs b/Src/CrispyWaffle/Log/Providers/EventLogProvider.cs
new file mode 100644
index 00000000..5643f6ed
--- /dev/null
+++ b/Src/CrispyWaffle/Log/Providers/EventLogProvider.cs
@@ -0,0 +1,176 @@
+using CrispyWaffle.Log.Adapters;
+using CrispyWaffle.Serialization;
+using System;
+
+namespace CrispyWaffle.Log.Providers
+{
+ ///
+ /// Class EventLogProvider. This class cannot be inherited.
+ /// Implements the
+ ///
+ ///
+ public sealed class EventLogProvider : ILogProvider
+ {
+ ///
+ /// Event log provider.
+ ///
+ private readonly EventLogAdapter _adapter;
+
+ #region ~Ctors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ public EventLogProvider(string source)
+ {
+ _adapter = new EventLogAdapter(source, string.Empty, Environment.MachineName, false, new EventIdProvider());
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ /// Name of the log.
+ public EventLogProvider(string source, string logName)
+ {
+ _adapter = new EventLogAdapter(source, logName, Environment.MachineName, false, new EventIdProvider());
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ /// Name of the log.
+ /// Name of the machine.
+ /// if set to true [manage event source].
+ /// The event identifier provider.
+ public EventLogProvider(string source, string logName, string machineName, bool manageEventSource,
+ IEventIdProvider eventIdProvider)
+ {
+ var provider = eventIdProvider ?? new EventIdProvider();
+ _adapter = new EventLogAdapter(source, logName, machineName, manageEventSource, provider);
+ }
+
+ #endregion
+
+ #region Implementation of ILogProvider
+
+ ///
+ /// Sets the log level of the instance
+ ///
+ /// The log level
+ public void SetLevel(LogLevel level)
+ {
+ _adapter.SetLevel(level);
+ }
+
+ ///
+ /// Logs the message with fatal level.
+ ///
+ /// The category.
+ /// The message.
+ public void Fatal(string category, string message)
+ {
+ _adapter.Fatal(message);
+ }
+
+ ///
+ /// Logs the message with error level
+ ///
+ /// The category
+ /// The message to be logged
+ public void Error(string category, string message)
+ {
+ _adapter.Error(message);
+ }
+
+ ///
+ /// Logs the message with warning level
+ ///
+ /// The category
+ /// The message to be logged
+ public void Warning(string category, string message)
+ {
+ _adapter.Warning(message);
+ }
+
+ ///
+ /// Logs the message with info level
+ ///
+ /// The category
+ /// The message to be logged
+ public void Info(string category, string message)
+ {
+ _adapter.Info(message);
+ }
+
+ ///
+ /// Logs the message with trace level
+ ///
+ /// The category
+ /// The message to be logged
+ public void Trace(string category, string message)
+ {
+ _adapter.Trace(message);
+ }
+
+ ///
+ /// Logs the message with trace level and shows exception details.
+ ///
+ /// The category.
+ /// The message to be logged.
+ /// The exception.
+ public void Trace(string category, string message, Exception exception)
+ {
+ _adapter.Trace(message, exception);
+ }
+
+ ///
+ /// Logs the exception details with trace level.
+ ///
+ /// The category.
+ /// The exception.
+ public void Trace(string category, Exception exception)
+ {
+ _adapter.Trace(exception);
+ }
+
+ ///
+ /// Logs the message with debug level
+ ///
+ /// The category
+ /// The message to be logged
+ public void Debug(string category, string message)
+ {
+ _adapter.Debug(message);
+ }
+
+ ///
+ /// Does nothing
+ ///
+ /// The category
+ /// Not used
+ /// Not used
+ public void Debug(string category, string content, string fileName)
+ {
+ _adapter.Debug(content, fileName);
+ }
+
+ ///
+ /// Does nothing
+ ///
+ /// Not used
+ /// The category
+ /// Not used
+ /// Not used
+ /// Not used
+ public void Debug(string category, T content, string identifier, SerializerFormat customFormat = SerializerFormat.NONE)
+ where T : class, new()
+ {
+ _adapter.Debug(content, identifier, customFormat);
+ }
+
+ #endregion
+ }
+}
diff --git a/Src/CrispyWaffle/Log/Providers/IEventIdProvider.cs b/Src/CrispyWaffle/Log/Providers/IEventIdProvider.cs
new file mode 100644
index 00000000..6606aef3
--- /dev/null
+++ b/Src/CrispyWaffle/Log/Providers/IEventIdProvider.cs
@@ -0,0 +1,15 @@
+namespace CrispyWaffle.Log.Providers
+{
+ ///
+ /// Interface IEventIdProvider
+ ///
+ public interface IEventIdProvider
+ {
+ ///
+ /// Computes the event identifier.
+ ///
+ /// The message.
+ /// System.UInt16.
+ ushort ComputeEventId(string message);
+ }
+}
diff --git a/Src/CrispyWaffle/Serialization/Adapters/BinarySerializerAdapter.cs b/Src/CrispyWaffle/Serialization/Adapters/BinarySerializerAdapter.cs
index ff86dc09..e099d7be 100644
--- a/Src/CrispyWaffle/Serialization/Adapters/BinarySerializerAdapter.cs
+++ b/Src/CrispyWaffle/Serialization/Adapters/BinarySerializerAdapter.cs
@@ -63,9 +63,8 @@ public T Load(string file) where T : class
var fileName = Path.GetFileName(file);
var folder = Path.GetDirectoryName(file);
- var are = new AutoResetEvent(false);
- var stream = LoadInternal(file, fileName, folder, are);
+ var stream = LoadInternal(file, fileName, folder);
return Deserialize(stream);
}
@@ -76,41 +75,50 @@ public T Load(string file) where T : class
/// The file.
/// Name of the file.
/// The folder.
- /// The are.
/// Stream.
- private static Stream LoadInternal(string file, string fileName, string folder, AutoResetEvent are)
+ private static Stream LoadInternal(string file, string fileName, string folder)
{
- Stream stream;
+ var autoResetEvent = new AutoResetEvent(false);
+
while (true)
{
try
{
- stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None);
- break;
+ return new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
- FileSystemWatcher watcher = null;
- try
- {
- watcher = new FileSystemWatcher
- {
- Filter = fileName, Path = folder,
- NotifyFilter = NotifyFilters.Attributes | NotifyFilters.DirectoryName | NotifyFilters.FileName |
- NotifyFilters.LastWrite | NotifyFilters.Size,
- EnableRaisingEvents = true
- };
- watcher.Changed += (o, e) => are.Set();
- are.WaitOne(new TimeSpan(0, 0, 0, 30));
- }
- finally
- {
- watcher?.Dispose();
- }
+ HandleLoadIoException(fileName, folder, autoResetEvent);
}
}
+ }
- return stream;
+ ///
+ /// Handles the load io exception.
+ ///
+ /// Name of the file.
+ /// The folder.
+ /// The automatic reset event.
+ private static void HandleLoadIoException(string fileName, string folder, AutoResetEvent autoResetEvent)
+ {
+ FileSystemWatcher watcher = null;
+ try
+ {
+ watcher = new FileSystemWatcher
+ {
+ Filter = fileName,
+ Path = folder,
+ NotifyFilter = NotifyFilters.Attributes | NotifyFilters.DirectoryName | NotifyFilters.FileName |
+ NotifyFilters.LastWrite | NotifyFilters.Size,
+ EnableRaisingEvents = true
+ };
+ watcher.Changed += (o, e) => autoResetEvent.Set();
+ autoResetEvent.WaitOne(new TimeSpan(0, 0, 0, 30));
+ }
+ finally
+ {
+ watcher?.Dispose();
+ }
}
///