2014-05-20 8 views
12

Wir haben einen .NET Windows-Dienst, der einen WCF-Dienst für eine Benutzerschnittstelle und andere Teile unseres Systems verfügbar macht. Es zielt auf .NET Framework 4.5 und verwendet SQLite 1.0.92 Binärdateien, um mit der zugrunde liegenden SQLite-Datenbank zu sprechen. Der Windows-Dienst stürzt jedoch (automatisch gestoppt) ab, nachdem er einige Zeit mit einer AccessViolationException (in Windows-Ereignisanzeige gefunden) in SQLite.Interop.dll ausgeführt wurde. Ich bin auf Artikel gestoßen, die in Connection über diese Ausnahme sprechen, aber in allen unseren Fällen begegnen wir dieser Ausnahme beim Abfragen oder Schreiben in die Datenbank mit den Methoden, die von unserem WCF-Dienst bereitgestellt werden. Der Stack-Trace ist wie folgt:SQLite AccessViolationException im WCF-Dienst

Application: OurServer.exe 
Framework Version: **v4.0.30319** 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.AccessViolationException 
Stack: 
    at System.Data.SQLite.UnsafeNativeMethods.sqlite3_bind_int(IntPtr, Int32, Int32) 
    at System.Data.SQLite.UnsafeNativeMethods.sqlite3_bind_int(IntPtr, Int32, Int32) 
    at System.Data.SQLite.SQLite3.Bind_Int32(System.Data.SQLite.SQLiteStatement, System.Data.SQLite.SQLiteConnectionFlags, Int32, Int32) 
    at System.Data.SQLite.SQLiteStatement.BindParameter(Int32, System.Data.SQLite.SQLiteParameter) 
    at System.Data.SQLite.SQLiteStatement.BindParameters() 
    at System.Data.SQLite.SQLiteCommand.GetStatement(Int32) 
    at System.Data.SQLite.SQLiteDataReader.NextResult() 
    at System.Data.SQLite.SQLiteDataReader..ctor(System.Data.SQLite.SQLiteCommand, System.Data.CommandBehavior) 
    at System.Data.SQLite.SQLiteCommand.ExecuteReader(System.Data.CommandBehavior) 
    at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(System.Data.CommandBehavior) 
    at DataAccess.Sqlite.ExecuteCommand(System.Collections.ObjectModel.Collection`1<System.String>, System.Collections.ObjectModel.Collection`1<System.Data.Common.DbParameter[]>) 
    at Data.Settings.Save(System.Collections.ObjectModel.Collection`1<Common.Operation>) 
    at DynamicClass.SyncInvokeSaveOperation(System.Object, System.Object[], System.Object[]) 
    at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(System.Object, System.Object[], System.Object[] ByRef) 
    at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(System.ServiceModel.Dispatcher.MessageRpc ByRef) 
    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(System.ServiceModel.Dispatcher.MessageRpc ByRef) 
    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(System.ServiceModel.Dispatcher.MessageRpc ByRef) 
    at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean) 
    at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(System.ServiceModel.Channels.RequestContext, Boolean, System.ServiceModel.OperationContext) 
    at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(System.ServiceModel.Channels.RequestContext, System.ServiceModel.OperationContext) 
    at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(System.IAsyncResult) 
    at System.Runtime.Fx+AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult) 
    at System.Runtime.AsyncResult.Complete(Boolean) 
    at System.Runtime.InputQueue`1+AsyncQueueReader[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Set(Item<System.__Canon>) 
    at System.Runtime.InputQueue`1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].EnqueueAndDispatch(Item<System.__Canon>, Boolean) 
    at System.Runtime.InputQueue`1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].EnqueueAndDispatch(System.__Canon, System.Action, Boolean) 
    at System.ServiceModel.Channels.SingletonChannelAcceptor`3[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Enqueue(System.__Canon, System.Action, Boolean) 
    at System.ServiceModel.Channels.ConnectionDemuxer+CompleteSingletonPreambleAndDispatchRequestAsyncResult.OnPreambleComplete(System.IAsyncResult) 
    at System.Runtime.Fx+AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult) 
    at System.Runtime.AsyncResult.Complete(Boolean) 
    at System.ServiceModel.Channels.ServerSingletonPreambleConnectionReader+CompletePreambleAsyncResult.OnWriteCompleted(System.Object) 
    at System.ServiceModel.Channels.SocketConnection.OnSendAsync(System.Object, System.Net.Sockets.SocketAsyncEventArgs) 
    at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
    at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(System.Net.Sockets.SocketError, Int32, System.Net.Sockets.SocketFlags) 
    at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) 
    at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) 

Wir sind die SQLite Baugruppen aus "SQLite-netFx45-binary-Bundle-Win32-2012-1.0.92.0" (heruntergeladen von http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki) verwenden. Die Assemblys werden als Teil des Windows-Dienstes gebündelt und sind nicht in GAC. Dieses Verhalten ist in 32-Bit- und 64-Bit-Computern konsistent. Zu Ihrer Information, wir verwenden die Mixed-Mode-Baugruppen NICHT.

Unsere Verbindungszeichenfolge:

Data Source=ourapp.db;Version=3;New=False;Compress=True;PRAGMA cache_size=20000; PRAGMA page_size=32768; PRAGMA synchronous=off" 

und die SQLite-Datenbank-Datei ist die Windows "Programdata" -Ordner.

Der Stacktrace zeigt die Framework-Version als "v4.0.30319" an, während wir die Zielversion in der Anwendungskonfiguration unseres Service explizit auf 4.5 gesetzt haben. Auf dem Computer sind jedoch beide Versionen installiert.

Außerdem schrieb ich eine einfache Konsolenanwendung, die dieselbe WCF-Dienstmethode aus mehreren Threads aufruft, aber nicht die gleiche AccessViolationException simulieren konnte. Daher glaube ich nicht, dass es sich um ein Lade- oder gleichzeitig zugreifendes Problem handeln könnte. Die Ausnahme scheint zufällig zu sein, und wir haben keine Möglichkeit, das Problem durchgängig neu zu reproduzieren, außer nur den Dienst auszuführen und darauf zu warten.

Alle Hinweise auf das, was dieses Problem verursachen könnte, werden sehr geschätzt.

UPDATE:

-Code für die beiden Varianten des ExecuteCommand verwendet:

public int ExecuteCommand(string query, params DbParameter[] parameters) 
    { 
     try 
     { 
      this.result = -1; 
      this.OpenConnection(); 
      this.command = new SQLiteCommand(query, this.connnection); 
      this.HandleParameters(parameters); 
      this.result = this.command.ExecuteNonQuery(); 
     } 
     catch (Exception ex) 
     { 
      this.result = -1; 
     } 
     finally 
     { 
      if (this.command != null) 
      { 
       this.command.Dispose(); 
      } 

      this.CloseConnection(); 
     } 

     return this.result; 
    } 


    public int ExecuteCommand(Collection<string> queries, Collection<DbParameter[]> parameters) 
    { 
     try 
     { 
      this.result = -1; 
      this.OpenConnection(); 
      this.command = new SQLiteCommand(); 
      this.command.Connection = this.connnection; 
      this.transaction = this.connnection.BeginTransaction(); 

      for (int i = 0; i < queries.Count; i++) 
      { 
       this.command.Parameters.Clear(); 
       this.command.CommandText = queries[i]; 
       this.command.CommandTimeout = this.timeOut; 
       this.command.Transaction = this.transaction; 

       DbParameter[] cmdParams = new DbParameter[] { }; 
       if (parameters != null) 
       { 
        cmdParams = parameters[i]; 
       } 

       this.HandleParameters(cmdParams); 
       this.result += this.command.ExecuteNonQuery(); 
      } 

      this.transaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
      if (this.transaction != null) 
      { 
       this.transaction.Rollback(); 
      } 

      this.result = -1; 
     } 
     finally 
     { 
      if (this.command != null) 
      { 
       this.command.Dispose(); 
      } 

      this.CloseConnection(); 
     } 

     return this.result; 
    } 

UPDATE 2: Code für Save-Methode

Collection<DbParameter[]> dbparameters = new Collection<DbParameter[]>(); 
    DbParameter[] dbparams; 
    SQLiteParameter sqlparams; 
    Collection<string> queries = new Collection<string>(); 
    int icount = 0; 

    foreach (Operation operation in operations) 
    { 
     icount = 0; 
     dbparams = new DbParameter[4]; 

     queries.Add("UPDATE table1 SET col1 = @Col1, col2 = @col2, " + 
        "Timestamp = @Timestamp WHERE Id = @Id"); 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Timestamp"; 
     sqlparams.Value = string.Format(CultureInfo.InvariantCulture, "{0:yyyy-MM-dd HH:mm:ss}", operation.Timestamp); 
     dbparams[icount++] = sqlparams; 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Id"; 
     sqlparams.Value = operation.Id; 
     dbparams[icount++] = sqlparams; 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Col1"; 
     sqlparams.Value = operation.Col1; 
     dbparams[icount++] = sqlparams; 

     sqlparams = new SQLiteParameter(); 
     sqlparams.DbType = DbType.String; 
     sqlparams.ParameterName = "@Col2"; 
     sqlparams.Value = operation.Col2; 
     dbparams[icount++] = sqlparams; 


     dbparameters.Add(dbparams); 
    } 


    return (DataAccess.Sqlite.ExecuteCommand(queries, dbparameters) > -1); 
+0

Können Sie Code für die Methoden 'DataAccess.SqlLite.ExecuteCommand' und' Data.Settings.Save' anzeigen? – nvoigt

+0

Ich habe den Beitrag mit dem Code für ExecuteCommand aktualisiert. Die Save-Methode erstellt Abfragen und ihre Parameter und ruft die überladene Methode auf, die eine Sammlung von Abfragen abruft. – Ananth

+0

Ein weiteres Update für die Save-Methode – Ananth

Antwort

1

Der Fehler bei der Anbieter zu verlieren Spur im Einklang davon sind die Verbindungen geöffnet:

  • Der Versuch, eine Verbindung zu schließen, die nicht
  • Der Versuch, eine Verbindung existiert zu verwenden, die nicht

Der Fehler mit Verbindungspooling wie ein Problem existiert aussieht, aber Ihre Verbindung String Connection Pooling und es nicht verwenden ist standardmäßig deaktiviert.

Funktioniert sonst noch auf dieselbe Datenbank zugreifen Wenn das Verbindungs-Pooling aktiviert ist?

Als erstes müssen Sie die Ausnahme protokollieren.

1

Ihre Klasse ist möglicherweise nicht threadsicher.Stellen Sie sicher, dass mehrere Threads die Save-Methode nicht gleichzeitig aufrufen.

Stellen Sie außerdem sicher, dass Sie IDisposable implementieren, um Ihr SQLiteConnection-Objekt zu entfernen, wenn es ein privates Mitglied Ihrer Klasse ist.