Hallo zusammen,
ich habe ein kleines Problem mit dem Verhalten des FilesystemWatchers. Bekanntlich werden für eine Datei die Events häufig mehrfach gefeuert (Es geht nur um das OnCreated).
Ich würde das Event aber gerne nur einmal verarbeiten, bis die Datei wieder von mir "freigegeben" wurde.
Ich habe im Handler ein Hashset erstellt und füge den Pfad hinzu. Sollte das fehlschlagen, würde die eigentliche Aktion nicht ausgelöst werden.
private HashSet<string> files = new HashSet<string>();
private void FileCreated(object sender, FilePathEventArgs e)
{
try
{
if (files.Add(e.FilePath))
//aktion();
}
catch (Exception ex)
{
//Test
}
}
Die Add Funktion ist natürlich nicht atomar und die Events werden so schnell gefeuert, das die Aktion dennoch 2 Mal ausgeführt wird.
Hat jemand eine andere Idee?
Danke
Event beim 1. Auslösen deabonnieren und beim "Freigeben" wieder abonnieren ist keine Option?
Hallo Rioma,
du könntest mit ner boolschen Variable abfragen, ob du das Event überhaupt ausführen sollst. Im finally setzt dus dann weider auf true
. Das ist zwar nicht schön, aber vielleicht hilft es ja.
Grad gefunden:
- Events being raised twice - An event will be raised twice if an event handler (AddHander FSW.Created, AddressOf FSW_Created) is explicitly specified. This is because, by default, the public events automatically call the respective protected methods (OnChanged, OnCreated, OnDeleted, OnRenamed). To correct this problem, simply remove the explicit event handler (AddHandler ...).
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Deabonnieren ist keine Option, da so potentielle andere Dateien übersehen werden.
Die Abfrage des booleschen Wertes müsste aber auf Dateiebene stattfinden. Da andere Dateien natürlich noch verarbeitet werden sollen. Ich denke ich werde hier ebenfalls das Problem haben, dass dies zu langsam ist.
Das Event habe ich nicht explizit abonniert.
_fileSystemWatcher.Created += FileSystemWatcherOnCreated;
Ich denke mein Problem ist hier erklärt:
Ich denke mein Problem ist hier erklärt:
Heisst das, du hast das Problem mit dem SO-Thread gelöst? Wenn ja: Wie? Oder heisst das nur, dass dies dein Problem noch besser beschreibt?
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Gelöst leider nicht. Ich wollte damit nur sagen, dass mein Problem nicht von den expliziten Eventhandlern kommt.
Absolut letzte Option wäre RX:
var watcher = new FileSystemWatcher("./");
Observable.FromEventPattern<FileSystemEventArgs>(watcher, "Changed")
.Throttle(new TimeSpan(500000))
.Subscribe(HandleChangeEvent);
watcher.EnableRaisingEvents = true;
Aber ich füge eine lib natürlich ungern für eine einzige Stelle hinzu.
Edit: Der Code ist aus dem Link
Dein Wunsch ist so vom FSW nicht abgedeckt. Dass bei einem Create zwei Events gefeuert werden, ist nichts neues und by design
Ergo musst Du das selbst umsetzen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hast Du schon mal das Deleted Event angeschaut?
Wenn man zum Beispiel mit Notepad++ eine Datei speichert, passiert folgendes:
Created -> Deleted -> Created
Könnte man wie folgt abfangen:
private static void watcher_Created(object sender, System.IO.FileSystemEventArgs e)
{
var time = File.GetCreationTimeUtc(e.FullPath);
long offset = 504911232000000000;
if (offset == time.Ticks) return;
Console.WriteLine("Created " + e.Name);
}
Das ich das nicht verhindern kann, ist mir bewusst.
Deswegen habe ich versucht, das Problem mit dem Hashset zu umgehen. Allerdings ohne erfolg. Ich bekomme 2 Mal ein true zurück und am Ende ist der Pfad nur einmal drin.
Füge ich die Datei nun ein weiteres Mal hinzu, gibt es keine Probleme. Die events sind einfach zu kurz hintereinander.
Race Condition, da Du in verschiedenen Thread bist und vergessen hast zu synchronisieren?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich hatte anfangs nicht daran gedacht, allerdings dann hinzugefügt.
Funktionieren tut es aber nur, wenn das Hashset static ist. Woran liegt das?
Ohne static befindet sich die variable auf Instanz-Ebene und davon sollte es nur eine geben.
Erzeugt wird diese von Topshelf:
HostFactory.Run(config =>
{
// Pass it to Topshelf
config.UseSimpleInjector(_container);
config.UseNLog();
config.Service<Service>(s => //Service ist die Instanz
{
s.ConstructUsingSimpleInjector();
s.WhenStarted((service, control) => service.Start(control));
s.WhenStopped((service, control) => service.Stop(control));
});
config.RunAsLocalSystem();
});