Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Webservice auf MONO/Linux ist nach einiger Zeit nicht mehr verfügbar aber durch Aufruf reaktivierbar
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

Webservice auf MONO/Linux ist nach einiger Zeit nicht mehr verfügbar aber durch Aufruf reaktivierbar

beantworten | zitieren | melden

Moin zusammen,
ich habe mal eine Frage zum Thema Webservice unter Mono/Linux.

Kurz zum Problem:
Auf einer Linux VM läuft mein Webservice (er führt Datenbank befehle aus).

Aber zwischendurch (keine regelmäßigen Abstände) bekomme ich die Exception:
Fehler
System.ServiceModel.FaultException: System.Data.SqlClient.SqlException: Server closed the connection. —-> Mono.Data.Tds.Protocol.TdsInternalException: Server closed the connection. —-> System.IO.IOException: Connection lost
at Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader () [0x00031] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsComm.cs:630
at Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket () [0x00000] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsComm.cs:604
at Mono.Data.Tds.Protocol.TdsComm.GetByte () [0x00011] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsComm.cs:477
at Mono.Data.Tds.Protocol.Tds.ProcessSubPacket () [0x00000] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs:1767
at Mono.Data.Tds.Protocol.Tds.NextResult () [0x0004a] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs:619
at Mono.Data.Tds.Protocol.Tds.SkipToEnd () [0x00005] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs:692
—- End of inner exception stack trace —-
at Mono.Data.Tds.Protocol.Tds.SkipToEnd () [0x0001d] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs:695
at Mono.Data.Tds.Protocol.Tds70.ExecRPC (TdsRpcProcId rpcId, System.String sql, Mono.Data.Tds.TdsMetaParameterCollection parameters, Int32 timeout, Boolean wantResults) [0x000ad] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds70.cs:487
at Mono.Data.Tds.Protocol.Tds80.Execute (System.String commandText, Mono.Data.Tds.TdsMetaParameterCollection parameters, Int32 timeout, Boolean wantResults) [0x0003e] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds80.cs:229
at System.Data.SqlClient.SqlCommand.Execute (Boolean wantResults) [0x0020b] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs:536
—- End of inner exception stack trace —-
at System.Data.SqlClient.SqlCommand.Execute (Boolean wantResults) [0x00252] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs:542
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery () [0x00015] in /var/tmp/portage/dev-lang/mono-2.10.9-r2/work/mono-2.10.9/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs:571
at HvsWerkApplAPI.Service1.InsertLieferschein (HvsWerkApplAPI.Responses.Lieferschein lfs, NummernKreis nrKreis) [0x00cce] in c:\SVN\Hvs\HVS.ng\WebServices\HvsWerkApplAPI\HvsWerkApplAPI\Service1.asmx.cs:4220

Nach einem öffnen der "Webseite" des Webservice geht es wieder.
Als wenn der Webservice in eine Art Standby Modus geht.

Webservice und Datenbank liegen auf dem gleichen PC

Moderationshinweis von Coffeebean (20.04.2016 - 11:46:42):

Du bist lang genug dabei: Benutze die richtige Code- und Error-Tags und wähle einen richtigen Titel. "Problem mit xyz" kann alles sein!

private Nachricht | Beiträge des Benutzers
Palin
myCSharp.de - Member



Dabei seit:
Beiträge: 1115

beantworten | zitieren | melden

Also für mich sieht es so aus als ob der SQL Server die Connection schließt.
Fehler
System.ServiceModel.FaultException: System.Data.SqlClient.SqlException: Server closed the connection

Öffnest du bei jedem Aufruf eine neue Connection und schießt sie nach der Verwendung?
Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

Hi,

Also die Verbindung hole ich mir hierher


public System.Data.SqlClient.SqlConnection GetSqlConnection()
{
    GC.Collect();
    System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("Server=127.0.0.1;Database=.....");
    conn.Open();
    return (conn);
}

Diese Methode nutze ich dann wie folgt:


public Int32 InsertLieferschein(Responses.Lieferschein lfs, MSSQL.NummernKreis nrKreis)
{
    System.Guid guId = System.Guid.NewGuid();
    using (System.Data.SqlClient.SqlConnection conn = this.sql.GetSqlConnection())
    {
        System.Data.SqlClient.SqlCommand cmd1 = null;
        System.Data.SqlClient.SqlCommand cmd2 = null;
        cmd1 = conn.CreateCommand();
        cmd1.CommandText = "INSERT INTO ...";
        cmd1.Parameters.AddWithValue("@pLf...",guId);
        // Rest des Befehl...

        cmd2 = conn.CreateCommand();
        cmd2.CommandText = "INSE....";
        cmd2.Parameters.AddWithValue("@pLf...",guId);
        // Rest des Befehl...

        System.Data.SqlClient.SqlTransaction transaction = null;
        try
        {
            transaction = conn.BeginTransaction(IsolationLevel.Serializable);

            cmd2.Transaction = transaction;
            cmd1.Transaction = transaction;

            cmd1.ExecuteNonQuery();
            cmd2.ExecuteNonQuery();

            transaction.Commit();

            return lfsNr;
        }
        catch (Exception ex)
        {
        }
    }
}

Aus meiner sich ok oder?

Danke schon mal für die Hilfe!
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15815
Herkunft: BW

beantworten | zitieren | melden

- Das GC.Collect ist unnötig, besonders hier sogar kontraproduktiv (When to call GC.Collect() - Rule #1: dont!
- Pooling aktiviert?
- Stichwort Repository Pattern und Single Responsibility wären hier als Stichwort angebracht. Eine Methode sollte nicht selbstständig die Verbindung aufbauen, sondern eine vorhandene Verbindung nutzen

Zudem sieht es mir nach einer Schichtverletzung aus, wenn Du einer Methode zwei verschiedene Objekte unterschiedlicher Anwendungsschichten gibst (Business Models und Entitäten) im DAL nutzt.
Das ist aber ein Architekturproblem, nicht der Auslöser der Fehlermeldung.
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

Hallo Abt,

Pooling aktiviert? -> Wo?

Was ist das genau, Repository Pattern und Single Responsibility?

Die Methode baut eine neue Verbindung auf, weil ich diese von verschiedenen Mehtoden nutze und der Code so nur einmal habe. Auch weil ich während ich mit einem DataReader arbeite neue Daten abfragen muss. Oder gibt es da eine bessere Lösung?

Hier ein Beispiel was ich meine:


Responses.StKunde kunde = null;

using (System.Data.SqlClient.SqlConnection conn = this.sql.GetSqlConnection())
{
    System.Data.SqlClient.SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = "SELECT * FROM StKunden WHERE isdeleted = 0 AND KdNr = @pKdNr";
    cmd.Parameters.AddWithValue("@pKdNr", kdNr);

    System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
                
    while (reader.Read())
    {
        kunde = new Responses.StKunde();

        for (Int32 indexCol = 0; indexCol < reader.FieldCount; indexCol++)
        {
            if (reader.IsDBNull(indexCol))
                continue;

            switch (reader.GetName(indexCol))
            {
                // STRING
                case "KdNr": kunde.KdNr = reader.GetString(indexCol); break;
                case "Name1": kunde.Name1 = reader.GetString(indexCol); break;
                //....
                case "AbsatzArtNr": kunde.AbsatzArt = this.GetAbsatzArt(kunde.AbsatzArtNr); break;
		//
		// REST DER METHODE...

private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Es könnte vllt daran liegen dass es aufgrund des Isolationslevels Serializable zu einer Verklemmung der Transaktionen auf dem Server kommt. Funktioniert es denn mit einem geringerem Level?
private Nachricht | Beiträge des Benutzers
Coffeebean
myCSharp.de - Team

Avatar #avatar-3295.gif


Dabei seit:
Beiträge: 2459
Herkunft: Deutschland/Schweiz

beantworten | zitieren | melden

Hallo Grimmbizkit,
Zitat von Grimmbizkit
Was ist das genau, Repository Pattern und Single Responsibility?

The Repository Pattern

Single responsibility principle

Gruss

Coffeebean
private Nachricht | Beiträge des Benutzers
Palin
myCSharp.de - Member



Dabei seit:
Beiträge: 1115

beantworten | zitieren | melden

Den leeren Catch Block solltest du auch entfernen, bzw da ein Rollback der Transaktion machen, damit diese beendet wird und die Connection wider Freigeben kann und den Fehler Loggen.
Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

@Palin
Der ctahc-Block ist normal mit einem Rollback gefüllt, habe ich hier nur weggelassen
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15815
Herkunft: BW

beantworten | zitieren | melden

Pooling wird im Connectionstring angegeben.www.connectionstrings.com
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

@ Abt

Ohne das GC.Collect() wird es ehr schlimmer, der gleiche Fehler kommt direkt. Nach 2-3 Aufrufen
private Nachricht | Beiträge des Benutzers
Coffeebean
myCSharp.de - Team

Avatar #avatar-3295.gif


Dabei seit:
Beiträge: 2459
Herkunft: Deutschland/Schweiz

beantworten | zitieren | melden

Hallo Grimmbizkit,

dann weist es dich noch direkter auf einen vorhandenen Fehler hin. Das ist gut! Das schlimmste sind Fehler, die schwer nachzustellen sind oder nur sporadsich auftreten. Wenn ein Fehler wenigstens regelmässig kommt, hat man schonmal viel gewonnen ;)


Wieso holst du das conn.open() nichtmal in das using? Der, der die Connection aufmacht sollte sie auch schliessen. Hier macht A die Connection auf und B (durch das Using) wieder zu.

Was ist this.sql? Ist das ein per DI verfügbarer Service, der scoped ist? Oder ist das ein Singleton irgendwo? Ich vermute mal, dass es da ganz woanders - was grundlegendes - nicht stimmt...

Gruss

Coffeebean
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15815
Herkunft: BW

beantworten | zitieren | melden

Zitat von Grimmbizkit
Ohne das GC.Collect() wird es ehr schlimmer
Dann ist bei euch was mächtig im Murks und wahrscheinlich der Grund dieses Problems hier. Mit GC.Collect kaschiert ihr das ganze, löst es aber nicht.
Löst den Grund und deckt ihn nicht einfach ab.

Lies den Link dazu. Deswegen hab ich ihn Dir gegeben.
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

@Coffeebean:

this.sql
ist nur eine Klasse damit ich die SqlBefehle nur einmal schreibe.


    public class MSSQL
    {
        public MSSQL()
        {

        }

        public System.Data.SqlClient.SqlConnection GetSqlConnection()
        {
            //GC.Collect();
            System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("Server=127.0.0.1;Database=...;");

            //conn.Open();
            return (conn);
        }
    }
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15815
Herkunft: BW

beantworten | zitieren | melden

Ja, der Code ist aber schon verbesserungswürdig.


public interface IMyDbProvider
{
     IDbConnection GetConnection();
}


public class MyMssqlProvider : IMyDbProvider
{
   public MyMssqlProvider (string connectionString) // Dependency Injection!
   {
   }

   public override IDbConnection GetConnection()
   {
      return new SqlConnection(_connectionString);
   }
}

Und entsprechend in der aufrufenden Klasse das Interface nutzen.

Bleibt dabei, dass ihr ein Grundlegendes Problem habt, das ihr lösen solltet.
GC.Collect als "Fix" zu sehen ist falsch (und fahrlässig).
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

@Abt

So läuft der Code bei mir.


    public interface IMyDbProvider
    {
        IDbConnection GetConnection();
    }
    
    public class MyMssqlProvider : IMyDbProvider
    {
        String connectionString;

        public MyMssqlProvider(string _connectionString) // Dependency Injection!
        {
            connectionString = _connectionString;
        }

        IDbConnection IMyDbProvider.GetConnection()
        {
            return new SqlConnection(connectionString);
        }
    }

Und der Using aufruf ist wohl auch Suboptimal:


using (System.Data.SqlClient.SqlConnection conn = (System.Data.SqlClient.SqlConnection) sql.GetConnection())
            {
                conn.Open();
                ...
            }

in der Klasse dann:


// DIESER CODE
        public System.Data.IDbConnection GetConnection()
        {
            System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("Server=127.0.0.1;Database=xxxxxxxxxx;User Id=sa;Password=xxxxxxxxxx;Pooling=false;");
            return conn;
        }
// STATT DIESEM
        public System.Data.SqlClient.SqlConnection GetSqlConnection()
        {
            //GC.Collect();
            System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("Server=127.0.0.1;Database=xxxxxxxxxx;User Id=sa;Password=xxxxxxxx;Pooling=false;");
            return conn;
            
            //conn.Open();

            //if (conn.State != System.Data.ConnectionState.Open)
            //    throw new Exception("ConnectionState = " + conn.State.ToString());

            //return (conn);
        }
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Grimmbizkit am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15815
Herkunft: BW

beantworten | zitieren | melden

Ich habe die Anmeldedaten in Deinem Code unkenntlich gemacht.
Du solltest sie jetzt trotzdem ändern...

Da seh ich direkt:
Deine Anwendung läuft als SQL Admin. Sowas macht man nicht.
Dein Pooling ist aus. Warum, sieht man hier nicht. Sinn?

Und zu meinem Code:
Die Interfaces waren Absicht und es sollte nur das grundlegend korrekte Vorgehen zeigen.

using (System.Data.SqlClient.SqlConnection conn = (System.Data.SqlClient.SqlConnection) sql.GetConnection())
zeigt mir aber, dass Du das Prinzip von Interfaces nicht so ganz durchschaut hast ;-)
private Nachricht | Beiträge des Benutzers
Grimmbizkit
myCSharp.de - Member



Dabei seit:
Beiträge: 310
Herkunft: Niederrhein

Themenstarter:

beantworten | zitieren | melden

Das Pooling ist wohl beim Copy&Paste entfallen, habe ich drin.

Ehrlich gesagt verliere ich so langsam den kompletten überblick :-(
private Nachricht | Beiträge des Benutzers