Bug #68263 System.InvalidOperationException in MySQL Connector.Net
Submitted: 4 Feb 2013 18:37 Modified: 29 May 2013 0:57
Reporter: Frederic MEYER Email Updates:
Status: Duplicate Impact on me:
None 
Category:Connector / NET Severity:S1 (Critical)
Version:6.6.4 OS:Any
Assigned to: Assigned Account CPU Architecture:Any
Tags: sessionprovider transaction

[4 Feb 2013 18:37] Frederic MEYER
Description:
In SessionProvider.cs, in several methods, the connection object is declared in the try block like this:

    public override void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout)
    {
      MySqlTransaction mySqlTransaction = null;
      try
      {
        using (MySqlConnection conn = new MySqlConnection(connectionString))
        {
...
        }
      }

If something wrong happens, the catch block tries to rollback the transaction, like this:

      catch (MySqlException e)
      {
        if (mySqlTransaction != null)
        {
          try
          {
            Trace.WriteLine("CreateUninitializedItem: Attempt to rollback");
            mySqlTransaction.Rollback();
          }
          catch (MySqlException ex)
          {
            HandleMySqlException(ex, "CreateUninitializedItem: Rollback Failed");
          }
        }
        HandleMySqlException(e, "CreateUninitializedItem");
      }

But the way the connection is declared, it has already been disposed once in the catch block, so this code thows an System.InvalidOperationException.

I think that the connection object should be declared before the first try block.

This pattern happens several times in the SessionProvider.cs source code, also in the CleanupOldSessions callback, hence the original bug report found here http://bugs.mysql.com/bug.php?id=67665.

Even though I already have described the problem in bug #67665, I recreated it here as a new bug item hoping that it will some more chances to be caught. Even though it is critical, Bug #67665 has no comments from Oracle team since it was first published, that is late november 2012.

How to repeat:
Simply follow the tutorial http://dev.mysql.com/doc/refman/5.5/en/connector-net-tutorials-asp-provider-session-state:

Web.config connectionString:

    <connectionStrings>
        <add name="SessionTestConnectionString" connectionString="server=localhost;port=3306;user id=root;password=password;database=session_test" providerName="MySql.Data.MySqlClient"/>
    </connectionStrings>

Web.config sessionState:
        <sessionState mode="Custom" cookieless="false" timeout="2" regenerateExpiredSessionId="true" customProvider="MySqlSessionStateProvider">
            <providers>
                <add name="MySqlSessionStateProvider" type="MySql.Web.SessionState.MySqlSessionStateStore, MySql.Web, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" applicationName="/" description="Session Test" connectionStringName="SessionTestConnectionString" writeExceptionsToEventLog="True" autogenerateschema="True" enableExpireCallback="False"/>
            </providers>
        </sessionState>

Get once the Default.aspx page,
Verify that the session is present in my_aspnet_sessions
Wait 2 minutes or so for the session to expire
Refresh the page in the browser and you get:

[InvalidOperationException: Connection must be valid and open to rollback transaction]
   MySql.Data.MySqlClient.MySqlTransaction.Rollback() +137
   MySql.Web.SessionState.MySqlSessionStateStore.CreateUninitializedItem(HttpContext context, String id, Int32 timeout) +486
   System.Web.SessionState.SessionStateModule.CreateUninitializedSessionState() +47
   System.Web.SessionState.SessionStateModule.GetSessionStateItem() +190
   System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData) +487
   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +66
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

If you refresh once more you get:

[InvalidOperationException: Nested transactions are not supported.]
   MySql.Data.MySqlClient.ExceptionInterceptor.Throw(Exception exception) +227
   MySql.Data.MySqlClient.MySqlConnection.Throw(Exception ex) +18
   MySql.Data.MySqlClient.MySqlConnection.BeginTransaction(IsolationLevel iso) +144
   MySql.Data.MySqlClient.MySqlConnection.BeginTransaction() +9
   MySql.Web.SessionState.MySqlSessionStateStore.GetSessionStoreItem(Boolean lockRecord, HttpContext context, String id, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags) +328
   MySql.Web.SessionState.MySqlSessionStateStore.GetItemExclusive(HttpContext context, String id, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actions) +31
   System.Web.SessionState.SessionStateModule.GetSessionStateItem() +117
   System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData) +487
   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +66
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

The only way to overcome this without restarting both MySQL Server and IIS is the following: using MySQLWorkbench, kill the connection, then delete the orphaned session in the my_aspnet_sessions table. Hit refresh and it works again.

If you do not kill the server connection first, you might no be able to delete the orphaned session because it's locked, and the client would time-out:

ERROR 1205: Lock wait timeout exceeded; try restarting transaction

SQL Statement:

DELETE FROM `session_test`.`my_aspnet_sessions` WHERE `SessionId`='nobozc2i3p5k1l45ofnec1zq' and`ApplicationId`='1'

This has been tested on Windows 7 x64, .NET 4.0, MySql 5.1.66 / 5.5.29 and Connector.NET 6.6.4. To the contrary of what have been said by the original reporter, we do face that issue also with the previous GA release 6.5.5 Connector.NET.

Suggested fix:
Declare the connection object earlier and outside the try/catch blocks.
[21 Feb 2013 16:13] Damien BRUN
Another way to get around this is to delete the session cookie. 

Anyway, website visitors do not know it (and should not have to), and thus prevents the use of mysql connector to handle sessions in production environment.
[15 Apr 2013 21:09] Frederic MEYER
Hi Fernando,

I saw you put that ticket in "Analyzing". It's been more than two months now... any chance this one could be fixed ?

Thanks!
[20 May 2013 17:20] Fernando Bichara
Hi,

See http://bugs.mysql.com/bug.php?id=67665.

Fernando
[29 May 2013 0:57] Fernando Gonzalez.Sanchez
Yes, this is a duplicate of 67665.