Перечисление System.Transactions с EnlistDuringPrepareRequired - почему Transaction.Current имеет нулевое значение во время вызова Prepare? - PullRequest
0 голосов
/ 08 апреля 2020

Итак, у меня есть собственный менеджер ресурсов, который я хочу подключить к System.Transaction. И важно, чтобы перед фиксацией транзакции я мог выполнить еще некоторую работу, связанную с этой транзакцией (в основном, откройте соединение с базой данных и сохраните некоторые изменения). Но это может произойти только в конце транзакции, поэтому я делаю это в пользовательском менеджере ресурсов с ISinglePhaseNotification / EnlistVolatile.

Проблема: когда метод Prepare вызывается в конце транзакции, транзакция .Ток уже нулевой. Таким образом, нет способа подключить новое соединение с базой данных к той же транзакции (и соединение не подключается автоматически, поскольку Transaction.Current отсутствует).

В документации Microsoft говорится, что при регистрации необходимо использовать EnlistmentOptions.EnlistDuringPrepareRequired, так что тогда можно будет заручиться дополнительными ресурсами во время подготовки. Но это невозможно, потому что Transaction.Current уже отсутствует. Это ошибка в. Net framework или я что-то не так делаю?

. Net Framework v4.7.2, на windows 10

Пример кода:

public class TestRM : ISinglePhaseNotification
        {
            public static Logger log = LogManager.GetCurrentClassLogger();

            public bool HadTran = false;
            public string Id { get; set; }
            public void Commit(Enlistment enlistment)
            {
                log.Info("Commit Current trans: {0} {1}", Id, Transaction.Current == null ? "---" : "jest:" + Transaction.Current.TransactionInformation.LocalIdentifier);
                enlistment.Done();
            }

            public void InDoubt(Enlistment enlistment)
            {
                log.Info("Doubt Current trans: {0} {1}", Id, Transaction.Current == null ? "---" : "jest:" + Transaction.Current.TransactionInformation.LocalIdentifier);
            }

            public void Prepare(PreparingEnlistment preparingEnlistment)
            {
                HadTran = Transaction.Current != null;
                log.Info("Prep Current trans: {0} {1}", Id, Transaction.Current == null ? "---" : "jest:" + Transaction.Current.TransactionInformation.LocalIdentifier);
                preparingEnlistment.Done();
            }

            public void Rollback(Enlistment enlistment)
            {
                log.Info("Rollb Current trans: {0} {1}", Id, Transaction.Current == null ? "---" : "jest:" + Transaction.Current.TransactionInformation.LocalIdentifier);
                enlistment.Done();
            }

            public void SinglePhaseCommit(SinglePhaseEnlistment singlePhaseEnlistment)
            {
                log.Info("SPC Current trans: {0} {1}", Id, Transaction.Current == null ? "---" : "jest:" + Transaction.Current.TransactionInformation.LocalIdentifier);
                singlePhaseEnlistment.Done();
            }
        }

        [TestMethod]
        public void TSDisposeTest()
        {
            var rm1 = new TestRM() { Id = "r1" };
            var rm2 = new TestRM() { Id = "r2" };
            using (var ts = new TransactionScope(TransactionScopeOption.Required))
            {
                Transaction.Current.EnlistVolatile(rm1, EnlistmentOptions.EnlistDuringPrepareRequired);
                Transaction.Current.EnlistVolatile(rm2, EnlistmentOptions.EnlistDuringPrepareRequired);
                ts.Complete();
            }
            Assert.IsTrue(rm1.HadTran);
            Assert.IsTrue(rm2.HadTran);

            Console.Write("TEST 2 rollback");
            rm1 = new TestRM() { Id = "r1" };
            rm2 = new TestRM() { Id = "r2" };
            using (var ts2 = new TransactionScope(TransactionScopeOption.Required))
            {
                Transaction.Current.EnlistVolatile(rm1, EnlistmentOptions.None);
                Transaction.Current.EnlistVolatile(rm2, EnlistmentOptions.EnlistDuringPrepareRequired);
            }
            Assert.IsFalse(rm1.HadTran);
            Assert.IsTrue(rm2.HadTran);
            Assert.IsTrue(false);
            Console.ReadLine();
        }


    }
...