Autor Beitrag
funcry
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: Mi 02.12.09 22:53 
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;


ausblenden volle Höhe 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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: 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.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: 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:

ausblenden volle Höhe 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: 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.


ausblenden volle Höhe 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(00900);
            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.