Hallo zusammen,
Ich habe ein Problem bezüglich der ObjectDisposedException, welches mir auf Anhieb nicht ersichtlich ist, wieso ich diese erhalte.
Situation:
Ich habe ein Xamarin Cross-Platform App, welche über eine API eine Verbindung zum Server aufbauen soll. Der Verbindungsaufbau wird dabei in einem extra Thread ausgeführt.
Rufe ich nun den Konstruktor der Schnittstelle auf, welcher sich automatisch verbindet, und der Verbindungsaufbau schlägt fehl, weil der Server derzeit nicht läuft, dann erhalte ich am Ende des Connect Threads die besagte Exception.
Beim verbinden wird die Schnittstelle IAsyncResult verwendet, um asynchon die Verbindung aufzubauen.
Der Aufruf der Connect-Funktion findet dabei im Konstruktor des AufgabenApi Objects statt.
Hier einmal der Konstruktor der AufgabenApi:
Die Connect Methode der Api sieht wie folgt aus:
Die Funktion GlobaleVariabeln.srv.Connect():
die Property IsConnected:
Was mich nun wundert ist, dass die Exception nicht überall auftritt. Verwende ich die selbe Funktion in Winforms, dann funktioniert alles wie es soll. Selbiges gilt für UWP.
Lediglich die Android Version der Cross-Plattform App wirft diese Exception.
Ich Vermute, dass es etwas mit dem IAsyncResult zu tun hat. Habt Ihr vielleicht eine Idee?
Und wenn ich gerade eh schon mal frage: Wo besteht der Unterschied zwischen .Close() beim Socket und .EndConnect()? Wie setzte ich EndConnect richtig ein, bzw. muss ich das überhaupt verwenden?
LG Marvin
Ich habe ein Problem bezüglich der ObjectDisposedException, welches mir auf Anhieb nicht ersichtlich ist, wieso ich diese erhalte.
Situation:
Ich habe ein Xamarin Cross-Platform App, welche über eine API eine Verbindung zum Server aufbauen soll. Der Verbindungsaufbau wird dabei in einem extra Thread ausgeführt.
Rufe ich nun den Konstruktor der Schnittstelle auf, welcher sich automatisch verbindet, und der Verbindungsaufbau schlägt fehl, weil der Server derzeit nicht läuft, dann erhalte ich am Ende des Connect Threads die besagte Exception.
Beim verbinden wird die Schnittstelle IAsyncResult verwendet, um asynchon die Verbindung aufzubauen.
Der Aufruf der Connect-Funktion findet dabei im Konstruktor des AufgabenApi Objects statt.
Hier einmal der Konstruktor der AufgabenApi:
C#-Quellcode
- /// <summary>
- /// Erstellt eine neue Instanz der AufgabenApi und verbindet sich mit dem angegeben Server.
- /// </summary>
- /// <param name="host"></param>
- /// <param name="port"></param>
- /// <exception cref="ArgumentException">Tritt auf, wenn der Port kleine als 0 oder größer als 99999 ist.</exception>
- /// <exception cref="Exceptions.ConnectionRefusedException">Tritt auf, wenn die Verbindung zum Server aufgrund von falschen Parametern nicht hergestellt werden konnte.</exception>
- public AufgabenApi(string host, int port)
- {
- this.Port = port;
- this.Host = host;
- Connect();
- }
Die Connect Methode der Api sieht wie folgt aus:
C#-Quellcode
- /// <summary>
- /// Stellt eine Verbindung zum AufgabenServer her.
- /// </summary>
- /// <returns>True wenn die Verbindung hergestellt wurde, ansonsten false.</returns>
- public bool Connect()
- {
- if (this.IsConnected) // Wenn die Verbindung bereits besteht, dann muss nicht erneut connected werden!
- return true;
- return GlobaleVariabeln.srv.Connect(Host, Port);
- }
Die Funktion GlobaleVariabeln.srv.Connect():
C#-Quellcode
- /// <summary>
- /// Verbindet sich mit dem angegebenen Server
- /// </summary>
- /// <param name="_host">Der Serverhost, entweder als IP oder als Name</param>
- /// <param name="_port">Der Port</param>
- /// <param name="timeout">Timeout in MS für den Verbidnungsaufbau</param>
- /// <exception cref="Exceptions.InvalidProtokollException">Tritt auf, </exception>
- /// <returns>True bei erfolgreicher Verbindnung</returns>
- public bool Connect(string _host, int _port, int timeout = 3000)
- {
- // Verbindung aufbauen
- #if FixServer
- _host = "WKS68"; // Wenn wir was testen wollen, läuft der Server sehr wahrscheinlich auf dem Entwicklerrechner, dieser wird hier angegeben
- // Bei Test in VM Muss der Port zur VM Weitergeleitet werden!!! Host bleibt dabei gleich!!!
- // Siehe https://blogs.oracle.com/scoter/networking-in-virtualbox-v2#NAT-PF für VirtualBox
- //_host = "127.0.0.1";
- #endif
- // Wir holen alle IPv4 Adressen des Hosts
- IPAddress[] hostIPs;
- try
- {
- hostIPs = Dns.GetHostEntry(_host).AddressList.Where(addr => addr.AddressFamily == AddressFamily.InterNetwork).ToArray();
- }
- catch (Exception)
- {
- // Der Host ist unbekannt!
- return false;
- }
- //hostIPs = hostIPs.Reverse().ToArray(); // Zum testen einer anderen IP am Start
- try
- {
- foreach (IPAddress IP in hostIPs)
- {
- connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- Debug.WriteLine("Verbinden mit {0}:{1}", _host, _port);
- IAsyncResult ar = connection.BeginConnect(IP, _port, null, connection);
- using (ar.AsyncWaitHandle)
- {
- if (ar.AsyncWaitHandle.WaitOne(timeout, true))
- {
- Debug.WriteLine("Verbunden mit {0}:{1}", IP, _port);
- }
- }
- if (IsConnected) // Prüfen ob die Verbindung noch besteht, da Virtuelle Netzwerkadpater ggf. alles annehmen, aber dann nicht verwalten und direkt disconnecten
- break;
- connection.Close();
- }
- }
- catch (SocketException ex)
- {
- if (ex.HResult == -2147467259) // Server hat die Verbindung abgelehnt, ggf. falsche Einstellungen!!
- {
- throw new Exceptions.ConnectionRefusedException("Die Verbindung zum AufgabenServer ist fehlgeschlagen. Bitte prüfen Sie die Verbindungseinstellungen!", _host, _port);
- }
- Debug.WriteLine("Verbindung abgelehnt");
- return false;
- }
- if (IsConnected)
- {
- empfangsThread = new Thread(new ThreadStart(Empfange))
- {
- Name = "Empfangsthread ServerConnection" // Wird angegeben, damit beim Debuggen der Thread leichter zugeordnet werden kann
- };
- empfangsThread.Start();
- Version serverProtokollVersion = null;
- ManualResetEvent ewh = new ManualResetEvent(false);
- ProtokollEventHandler handler = (object sender, ProtokollEventArgs e) =>
- {
- serverProtokollVersion = e.ProtokollVersion;
- ewh.Set();
- };
- this.ProtokollReceived += handler;
- // Protokoll initialisieren
- ServerProtokoll serverProtokoll = new ServerProtokoll()
- {
- ProtokollNachricht = new NachrichtenTypen.ProtokollNachricht()
- };
- serverProtokoll.Send();
- ewh.WaitOne();
- this.ProtokollReceived -= handler;
- ewh.Close();
- if (serverProtokollVersion > GlobaleVariabeln.ProtokollVersion)
- throw new Exceptions.InvalidProtokollException("Die Protokollversion des Clients ist veraltet. Bitte führen Sie ein Update der Aufgabenlibrary durch.");
- else if (serverProtokollVersion < GlobaleVariabeln.ProtokollVersion)
- throw new Exceptions.InvalidProtokollException("Die Protokollversion des Servers ist veraltet. Bitte führen Sie ein Update der Aufgabenlibrary durch.");
- OnConnected(EventArgs.Empty);
- }
- return IsConnected;
- }
die Property IsConnected:
C#-Quellcode
- /// <summary>
- /// Ruft einen Wert ab, der angibt, ob die Verbindung zum Server besteht.
- /// </summary>
- public bool IsConnected
- {
- get
- {
- try // Wir Try-Catchen, weil beim Receive ggf. die Verbindung abbrechen kann!
- {
- if (connection != null && connection.Connected)
- {
- /* pear to the documentation on Poll:
- * When passing SelectMode.SelectRead as a parameter to the Poll method it will return
- * -either- true if Socket.Listen(Int32) has been called and a connection is pending;
- * -or- true if data is available for reading;
- * -or- true if the connection has been closed, reset, or terminated;
- * otherwise, returns false
- */
- // Detect if client disconnected
- if (connection.Poll(0, SelectMode.SelectRead))
- {
- byte[] buff = new byte[1];
- if (connection.Receive(buff, SocketFlags.Peek) == 0)
- {
- // Client disconnected
- return false;
- }
- else
- {
- return true;
- }
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- catch
- {
- return false;
- }
- }
- }
Was mich nun wundert ist, dass die Exception nicht überall auftritt. Verwende ich die selbe Funktion in Winforms, dann funktioniert alles wie es soll. Selbiges gilt für UWP.
Lediglich die Android Version der Cross-Plattform App wirft diese Exception.
Ich Vermute, dass es etwas mit dem IAsyncResult zu tun hat. Habt Ihr vielleicht eine Idee?
Und wenn ich gerade eh schon mal frage: Wo besteht der Unterschied zwischen .Close() beim Socket und .EndConnect()? Wie setzte ich EndConnect richtig ein, bzw. muss ich das überhaupt verwenden?
LG Marvin