5

I have a service running, that is connected to a few clients. It has been up and running for weeks and this function is called many times every minute, I have a few catches in the different function, but this exception made it all the way to crash. I never seen the issue before. Whan can make this occure?

Stack:

Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
Stack:
   at System.Data.OleDb.OleDbServicesWrapper.GetDataSource(System.Data.OleDb.OleDbConnectionString, System.Data.OleDb.DataSourceWrapper ByRef)
   at System.Data.OleDb.OleDbConnectionInternal..ctor(System.Data.OleDb.OleDbConnectionString, System.Data.OleDb.OleDbConnection)
   at System.Data.OleDb.OleDbConnectionFactory.CreateConnection(System.Data.Common.DbConnectionOptions, System.Object, System.Data.ProviderBase.DbConnectionPool, System.Data.Common.DbConnection)
   at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(System.Data.Common.DbConnection, System.Data.ProviderBase.DbConnectionPoolGroup)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(System.Data.Common.DbConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(System.Data.Common.DbConnection, System.Data.ProviderBase.DbConnectionFactory)
   at System.Data.OleDb.OleDbConnection.Open()
   at EServer.Database.DBManager.DoesObjectExsist(System.String)
   at EServer.Database.DBManager.setObjectOnline(System.String, Boolean, System.String, System.String)
   at EServer.Network.SocketListener.handleToDo()
   at EServer.Network.Token.ProcessData(System.Net.Sockets.SocketAsyncEventArgs)
   at EServer.Network.SocketListener.ProcessReceive(System.Net.Sockets.SocketAsyncEventArgs)
   at EServer.Network.SocketListener.OnIOCompleted(System.Object, System.Net.Sockets.SocketAsyncEventArgs)
   at System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(System.Net.Sockets.SocketAsyncEventArgs)
   at System.Net.Sockets.SocketAsyncEventArgs.ExecutionCallback(System.Object)
   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*)

Code:

public bool DoesObjectExsist(String ID)
        {
            try
            {    
                String connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + dbPath + "'";
                string mySelectQuery = "SELECT * FROM Object WHERE ID = \"" + ID + "\"";

                OleDbConnection myConnection = new OleDbConnection(connectionString);
                OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection);
                myConnection.Open();
                OleDbDataReader myReader = myCommand.ExecuteReader();
                try
                {
                    while (myReader.Read())
                    {
                        return true;
                    }
                }
                finally
                {
                    myReader.Close();
                    myConnection.Close();
                }
                return false;
            }
            catch (Exception e)
            {
                return false;
            }
        }
Nick3
  • 639
  • 1
  • 14
  • 40
  • 1
    Using an Access database in a multi-user service scenario is very unwise. It just isn't bullet-proof enough for such an application. You'll need help from Microsoft Support to find a solution, they'll need at least a minidump to work from. But high odds they'll just tell you to stop doing this because they won't support it. Consider at least SQL Server Express as a substitute. – Hans Passant Oct 22 '13 at 12:37

2 Answers2

5

EF Core Update

The followings sections are a bit dated and are about EF6 and .NET Framework 4.x. Nowadays, if you are using .NET (Core), use the EntityFrameworkCore.Jet EF Core provider. Use the latest prerelease, that references the 5.0.0 OLE DB libraries, that contain some major bugfixes.

AccessViolationException

This issue is a bug within the ACE 2010 engine. A workaround can be found in the original bug report on microsoft connect (see FranzT):

In my Applicationn I have the same problem. MS Access DB is a backend for this app(C#, .NET 2.0, VS 2005).

When in connection string as provider OLEDB.4.0 is used, it works fine. When the data access provider is ACE.OLEDB.12 I get an Exception if OpenFileDialog is used.

In connection string is possibel to set many parameters, OLE DB Services too.

When OLE DB Services=default (-13, pooling disabled) I get the Exception. When OLE DB Services=EnableAll (-1, pooling enabled) it works fine.

If I set OLE DB Services=-2 (EnableAll without pooling) I get the Exception.

My workaround is: set the OLE DB services=-1(EnableAll).

The workaround is based on the research of a microsoft forum user by the name of Elmar Boye, who goes into detail about the nature of the issue (though in German):

https://social.msdn.microsoft.com/Forums/de-DE/500055e5-6189-418c-b119-fdc0367e0969/accessviolationexception-bei-openfiledialog-nach-ffnen-und-schlieen-einer-2-form?forum=dotnetframeworkde

Basically, the ACE 2010 engine is accessing memory it doesn't own. And if the database is already unloaded at the time the engine accesses the memory, the exception is thrown. To workaround the issue, connection pooling can be used, since it keeps the database connection open and therefore the database in memory. It can be enabled using different combinations of OLE DB Services flags.

A good flag value is the original default, which enables all services (though this default seems to be overwritten by a registry key, which is why it makes sense to manually provide the value in the connection string):

OLE DB Services=-1

Though the bug report addresses a problem within the open file dialog, the root cause is the same as for other AccessViolationException cases using the ACE 2010 provider for Access.

There is also a link to a Hotfix that supposedly fixes the issue.

By the way, this exception does not occur using the Microsoft.Jet.OLEDB.4.0 provider.

JetEntityFrameworkProvider

For those like me who are using the JetEntityFrameworkProvider by bubibubi make sure that you are using the workaround in your production connection string, but not in your connection string you use for applying database migrations, because it will throw a OleDbException E_UNEXPECTED(0x8000FFFF) on the second Update-Database command while trying to open the database and will lockup the Package Manager Console on every command execution thereafter (until you restart Visual Studio).

Access and multi user scenarios

Access is build for simultaneous multi user access over a network share. So this is a scenario that is explicitly supported. @Hans Passant and @user2905764

lauxjpn
  • 4,749
  • 1
  • 20
  • 40
0

Why dont you make it more sumpler by using this. If would greate if you wrap connection, command and reader objects inside a using statement block. See usage of using.

Update

Sorry , I saw this couple of minutes ago that, you are using Access db for Services, which is, I think completely insane. Since services are consumed by various clients at a time so it might lead to inconsistency. So, as Hans Passant suggested in his comment, kindly go for Sql Server Express or MySql like Server-Oriented database for such scenarios.

public bool DoesObjectExsist(String ID)
        {
         bool result=false;
            try
            {    
                String connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + dbPath + "'";
                string mySelectQuery = "SELECT Count(*) FROM Object WHERE ID = ?";

                OleDbConnection myConnection = new OleDbConnection(connectionString);

                OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection);
                command.Parameters.AddWithValue("@id",ID);
                myConnection.Open();
                OleDbDataReader myReader = myCommand.ExecuteReader();
                try
                {
                   if(reader.HasRows)
                        result=true;

                }
                finally
                {
                    myReader.Close();
                    myConnection.Close();
                }

            }
            catch (Exception e)
            {
               //log exception
            }
            return result;
        }
Community
  • 1
  • 1