Entwickler-Ecke
Datenbanken (inkl. ADO.NET) - Firebird DBEvent Problem
funcry - Mi 02.12.09 22:53
Titel: Firebird DBEvent Problem
Folgendes Problem habe cih derzeit. Ich greife auf eine aktuelle Firebird-DB aus c# heraus mittels des aktuellen .net Providers zu.
Von der DB habe ich zwei Events abonniert. Wenn die Anwendung l+uft funktioniert alles mehrere Stunden lang, dann plötzlich funktioniert der Event-Mechanismus nicht mehr.
Jetzt suche ich nach der Ursache, oder alternativ nach einem Workaround. Falls jemand schon das gleiche Problem hatte, wäre ich für einen Tipp dankbar.
Hier die Klasse welche ich zum Abrufen der DB-Events erstellt habe:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FirebirdSql.Data.FirebirdClient;
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 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:
| public class DBEvents : IDisposable { public event EventHandler ResultInserted; protected virtual void OnResultInserted() { EventHandler resultInserted = this.ResultInserted; if (resultInserted != null) resultInserted(this, EventArgs.Empty); }
public event EventHandler MessageInserted; protected virtual void OnMessageInserted() { EventHandler messageInserted = this.MessageInserted; if (messageInserted != null) messageInserted(this, EventArgs.Empty); }
private bool disposed; private FbConnection con = new FbConnection(Properties.Settings.Default.ConnectionString);
public string Initialize() { string result = String.Empty;
try { this.con.Open();
FbRemoteEvent remoteEventMessageInserted = new FbRemoteEvent(con, new string[] { "MESSAGE_INSERTED" }); remoteEventMessageInserted.RemoteEventCounts += (sender, e) => this.OnMessageInserted(); remoteEventMessageInserted.QueueEvents();
FbRemoteEvent remoteEventResultInserted = new FbRemoteEvent(con, new string[] { "RESULT_INSERTED" }); remoteEventResultInserted.RemoteEventCounts += (sender, e) => this.OnResultInserted(); remoteEventResultInserted.QueueEvents(); } catch (FbException e) { result = e.Message; }
return result; }
public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { this.con.Close(); this.con.Dispose(); this.con = null; } } this.disposed = true; } } |
Und hier der Konstruktor der GUI-Klasse welche die Events verarbeitet:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| public PageSupervisor(Message message) { this.Language = XmlLanguage.GetLanguage(System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag); InitializeComponent();
this.dbEvents.Initialize(); this.dbEvents.ResultInserted += (sender, e) => this.resultsInserted();
} |
Kha - Mi 02.12.09 23:32
Habe keine Ahnung von FB, aber werden möglicherweise die FbRemoteEvent-Objekte irgendwann vom GC abgeräumt? Speicher sie lieber mal in einem Klassenfeld.
funcry - Mi 02.12.09 23:46
Das klingt logisch, aber denke das habe ich bereits getan. Hier ein umfangreicherer Code-Abschnitt der GUI-klasse, welche meine DBEvents Klasse nutzt. Sowohl DBEvents als auch meine GUI-Klasse implementieren IDisposable.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| public partial class PageSupervisor : Page, IDisposable { private bool disposed; private Message message; private DBEvents dbEvents = new DBEvents();
public PageSupervisor(Message message) { this.Language = XmlLanguage.GetLanguage(System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag); InitializeComponent();
this.message = message; this.viewbox1.Child = this.userControlLed;
this.dbEvents.Initialize(); this.dbEvents.ResultInserted += (sender, e) => this.resultsInserted(); } |
Kha - Do 03.12.09 00:06
Das habe ich gesehen, ändert aber wenig daran, dass du auf die FbRemoteEvent-Instanzen keine Referenz hältst :nixweiss: .
Wenn die FbConnection das bereits macht, ist es so natürlich ok, aber das weiß ich eben nicht.
funcry - Do 03.12.09 00:12
Oh - jetzt stand ich auf dem Schlauch :-) In der DBEvents Klasse werde ich Klassenfelder der FBRemoteEvens machen. Morgen nach ein paar Stunden Laufzeit kann ich berichten ob dies die Lösung war. Danke für den Hinweis.
funcry - Do 03.12.09 18:49
Es brachte leider nicht die gewünschte Lösung. Daher habe ich die klassenfelder inzwischen wieder herausgenommen und einen Workaround implementiert. Die aktualisierte Klasse sieht nun so aus, ich bin gespannt ob damit das problem behoben ist:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 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: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87:
| using System; using System.Collections.Generic; using System.Linq; using System.Text; using FirebirdSql.Data.FirebirdClient; using System.Windows.Forms;
namespace muh { public class DBEvents : IDisposable { public event EventHandler ResultInserted; protected virtual void OnResultInserted() { EventHandler resultInserted = this.ResultInserted; if (resultInserted != null) resultInserted(this, EventArgs.Empty); }
public event EventHandler MessageInserted; protected virtual void OnMessageInserted() { EventHandler messageInserted = this.MessageInserted; if (messageInserted != null) messageInserted(this, EventArgs.Empty); }
private bool disposed; private Timer timerDBEventsWorkaround = new Timer(); private FbConnection con;
public void Initialize() { this.con = new FbConnection(Properties.Settings.Default.ConnectionString); this.con.Open();
this.registerEvents();
this.timerDBEventsWorkaround.Interval = 600 * 1000; this.timerDBEventsWorkaround.Tick += (sender1, e1) => this.timerDBEventsWorkaroundTick(); }
private void registerEvents() { FbRemoteEvent remoteEventMessageInserted; FbRemoteEvent remoteEventResultInserted;
remoteEventMessageInserted = new FbRemoteEvent(con, new string[] { "MESSAGE_INSERTED" }); remoteEventMessageInserted.RemoteEventCounts += (sender, e) => this.OnMessageInserted(); remoteEventMessageInserted.QueueEvents();
remoteEventResultInserted = new FbRemoteEvent(con, new string[] { "RESULT_INSERTED" }); remoteEventResultInserted.RemoteEventCounts += (sender, e) => this.OnResultInserted(); remoteEventResultInserted.QueueEvents(); }
private void timerDBEventsWorkaroundTick() { this.con.Close(); this.con.Dispose(); this.con = new FbConnection(Properties.Settings.Default.ConnectionString); this.con.Open();
this.registerEvents(); }
public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { this.con.Close(); this.con.Dispose(); this.con = null; } } this.disposed = true; } } } |
funcry - Mo 07.12.09 10:17
Abschliessend möchte ich noch die aktuelle Lösung posten.
Edit:
Mit dem derzeitigen .net Provider 2.5.1 ist auch diese Variante nicht zufriedenstellend.
Teilweise kommen IscExceptions welche eigentlich überhaupt nicht zutage treten dürften, da diese private sind und nicht behandelt werden können. Ein weiteres Problem ist daß QueueEvents manchmal zum Hängen führt. Auch im Debug-Modus und auch wenn man zeilenweise debuggt. Die einzige Hoffnung bleibt ein neuer .net Provider der diese Probleme löst.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 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: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95:
| using System; using System.Collections.Generic; using System.Linq; using System.Text; using FirebirdSql.Data.FirebirdClient; using System.Windows.Threading;
namespace muh { public class DBEvents : IDisposable { public event EventHandler ResultInserted; protected virtual void OnResultInserted() { EventHandler resultInserted = this.ResultInserted; if (resultInserted != null) resultInserted(this, EventArgs.Empty); }
private bool disposed; private DispatcherTimer timerDBEventsWorkaround = new DispatcherTimer(); private FbConnection con; private FbRemoteEvent remoteEventResultInserted;
public void Initialize() { this.registerEvents();
this.timerDBEventsWorkaround.Interval = new TimeSpan(0, 0, 900); this.timerDBEventsWorkaround.Tick += (sender, e) => this.timerDBEventsWorkaroundTick(); this.timerDBEventsWorkaround.Start(); }
private void registerEvents() { this.con = new FbConnection(Properties.Settings.Default.ConnectionString);
try { if (this.con.State != System.Data.ConnectionState.Open) this.con.Open(); } catch (FbException) { return; }
this.remoteEventResultInserted = new FbRemoteEvent(con, new string[] { "RESULT_INSERTED" }); this.remoteEventResultInserted.RemoteEventCounts += (sender, e) => this.OnResultInserted(); this.remoteEventResultInserted.QueueEvents(); }
private void timerDBEventsWorkaroundTick() { if (this.remoteEventResultInserted != null) this.remoteEventResultInserted.CancelEvents();
if (this.con != null) { if (this.con.State == System.Data.ConnectionState.Open) this.con.Close();
this.con.Dispose(); this.con = null; }
this.registerEvents(); }
public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { if (this.con != null) { if (this.con.State == System.Data.ConnectionState.Open) this.con.Close();
this.con.Dispose(); this.con = null; } } } this.disposed = true; } } } |
Edit: Nochmal überarbeitet.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!