Search code examples
c#membershiprolestransactionscope

TransactionScope with Membership and Roles calls in same block (way to use only one connection?)


I have calls to the Membership API and the Roles API in the same transaction scope. I've read that opening more than one connection causes escalation requiring distributed transactions to be enabled, so I'm looking for a way to open one connection and share it with: Membership, roles, my own calls.

Here's the working code that causes unwanted escalation:

public static void InsertUser(string userName, string email, string roleName, int contactId, string comment)
      {
         /*
          * Exceptions thrown here are caught in the DetailView's event handler and piped to the UI.
          */

         using(var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
         {
            string password = Membership.GeneratePassword(Membership.MinRequiredPasswordLength, Membership.MinRequiredNonAlphanumericCharacters);
            const string passwordQuestion = "Should you change your password question?";
            const string passwordAnswer = "yes";
            MembershipCreateStatus status;
            MembershipUser user = Membership.CreateUser(userName, password, email, passwordQuestion, passwordAnswer, true, out status);

            if(user == null)
            {
               throw new Exception(GetErrorMessage(status));
            }

            // Flesh out new user
            user.Comment = comment;
            Membership.UpdateUser(user);

            // Give user a role
            Roles.AddUserToRole(user.UserName, roleName);

            // Create bridge table record
            Guid userId = (Guid)ExceptionUtils.ThrowIfDefaultValue(user.ProviderUserKey, "ProviderUserkey is null!");
            insertIntoAspnet_Users_To_Contact(userId, contactId);

            // Send welcome email
            EmailUtils.SendWelcomeEmailFromAdmin(userName, email, password, passwordQuestion, passwordAnswer, roleName);

            transactionScope.Complete();
         }
      }

Thanks


Solution

  • If you have SQL2008 or higher, it can handle a transaction across multiple connections, without escalating to MSDTC. The requirement is that you use exactly the same connection string for all connections.

    If you're on a lower SQL server version I think that you loose. I investigated this a few months ago and found no way to handle it, so I ended up skipping the transactions and implementing my own error handling instead. The customer had SQL2005 and an upgrade was not possible.