Подтвердить что ты не робот

Запуск System.Web.Providers в TransactionScope

Мы пытаемся интегрировать управление членством System.Web.Providers в транзакцию с использованием System.Transactions.TransactionScope и получать следующее сообщение об ошибке:

The operation is not valid for the state of the transaction.

Завершена в исключение со следующим, более запутанным сообщением:

The provider did not return a ProviderManifestToken string.

Прежде чем кто-нибудь спросит, да, мы проверили, что строка подключения верна, и пользователь, которого мы используем для подключения к db, имеет соответствующие разрешения. Если мы попытаемся вызвать Memberhip.CreateUser() из блока TransactionScope, он будет работать. Поместите его в TransactionScope, и он не работает.

Там, кажется, есть удивительно мало информации о Универсальном Провайдере. Практически все, что вы видите, - это ссылки на страницу NuGet и сообщение блога Скотта Ханзельмана с июня.

Кто-нибудь знает, как заставить System.Web.Providers участвовать в транзакции?

Спасибо.

Здесь полная stacktrace, если это полезно:

System.Data.ProviderIncompatibleException was unhandled by user code
  Message=The provider did not return a ProviderManifestToken string.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
       at System.Web.Providers.Entities.ModelHelper.GetStorageMetadata(String providerName, DbConnection connection, String ssdl)
       at System.Web.Providers.Entities.ModelHelper.CreateMetadataWorkspace(String providerName, DbConnection connection, String csdl, String ssdl, String msl)
       at System.Web.Providers.Entities.ModelHelper.CreateEntityConnection(ConnectionStringSettings setting, String csdl, String ssdl, String msl)
       at System.Web.Providers.Entities.ModelHelper.CreateMembershipEntities(ConnectionStringSettings setting)
       at System.Web.Providers.DefaultMembershipProvider.Membership_CreateUser(String applicationName, String userName, String password, String salt, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, DateTime& createDate, Boolean uniqueEmail, Int32 passwordFormat, Object& providerUserKey)
       at System.Web.Providers.DefaultMembershipProvider.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object providerUserKey, MembershipCreateStatus& status)
       at System.Web.Security.Membership.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object providerUserKey, MembershipCreateStatus& status)
       at WcfLoginRegister.RegistrationService.RegisterUser(RegisterUserRequest request) in C:\Users\rmacgrogan\dev\pallas\parthenon\sandbox\FbEntityTypeTester\WcfLoginRegister\RegistrationService.svc.cs:line 43
       at SyncInvokeRegisterUser(Object , Object[] , Object[] )
       at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
       at     System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
  InnerException: System.Transactions.TransactionException
       Message=The operation is not valid for the state of the transaction.
       Source=System.Transactions
       StackTrace:
            at     System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
            at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
            at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
            at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
            at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
            at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
            at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
            at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
            at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
            at System.Data.SqlClient.SqlConnection.Open()
            at System.Data.SqlClient.SqlProviderServices.UsingConnection(SqlConnection sqlConnection, Action`1 act)
            at System.Data.SqlClient.SqlProviderServices.UsingMasterConnection(SqlConnection sqlConnection, Action`1 act)
            at System.Data.SqlClient.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection)
            at System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
   InnerException: 

Update

Я сделал упрощенный тест, чтобы получить лучший доступ к реальной основной ошибке, и Бахри Гунгор прав, что основная проблема заключается в том, что MSDTC не включен.

Однако, поскольку я пытаюсь запустить этот код в проекте Azure, и поскольку Azure не поддерживает распределенные транзакции, я застрял, используя уродливое обходное решение. Все записи участников должны выполняться в отдельной транзакции, что довольно неудачно.

Спасибо всем за вашу помощь.

4b9b3361

Ответ 1

Я не пробовал использовать TransactionScope с ASPNet Membership Services, однако все, что откроет другую транзакцию (даже второе подключение к базе данных), автоматически инициализирует транзакцию MSDTC. Если MSDTC не настроен на машине (я предполагаю, что ваш веб-сервер), транзакция не может быть успешно создана.

В разделе "Администрирование" имеется инструмент управления "Службы компонентов" ( "Панель управления" → "Система и безопасность" - "Администрирование" ). Как только инструмент откроется, вы увидите "Службы компонентов" с левой стороны. Откройте службы компонентов → Компьютеры → Мой компьютер → Координатор распределенных транзакций → Локальный код неисправности (щелкните правой кнопкой мыши и выберите "Свойства" ). Выберите вкладку "Безопасность".

Убедитесь, что связь "Управление транзакциями" имеет параметр "Разрешить входящий" и "Разрешить исходящий". Необходимо также проверить доступ к сети DTC. Я не могу быть более конкретным в отношении других параметров, потому что для вашей конкретной среды могут потребоваться разные настройки для других переменных.

Я считаю, что происходит то, что ваш доступ к службам членства ASPNet (имеющим собственную конфигурацию SQL Server) способствует транзакции транзакции MSDTC, а некоторые настройки (безопасность или конфигурация MSDTC) мешают ей преуспеть, Вы найдете все виды литературы по поиску и устранению неполадок MSDTC с помощью простого поиска Google (многие из которых разрешены при переполнении стека). Тем не менее, я сначала проверю конфигурацию компонентов компонентов и убедитесь, что вы можете выполнить распределенную транзакцию.

Ответ 2

Это может быть вызвано, когда вы вложили TransactionScopes:

        using (var ts = new TransactionScope())
        {
            using(var tsInner1 = new TransactionScope())
            {
                //OOPS, I forgot to call Complete() or Rollback()
            }
            using (var tsInner2 = new TransactionScope())
            {
                //Any db action followed by a "Complete" will cause this error
                tsInner2.Complete();
            }
        }

Но я не могу быть уверен, не увидев код, который вызвал ошибку.