protected InternalEnlistment(System.Transactions.Enlistment enlistment, IEnlistmentNotification twoPhaseNotifications)
 {
     this.enlistment = enlistment;
     this.twoPhaseNotifications = twoPhaseNotifications;
     this.enlistmentId = 1;
     this.traceIdentifier = EnlistmentTraceIdentifier.Empty;
 }
        public void TestInitialize()
        {
            target = new TransactionEnlistmentHelper();

            ensureTransaction = true;
            options = EnlistmentOptions.None;

            enlistmentNotification = MockRepository.GenerateMock<IEnlistmentNotification>();
            enlistmentNotification.Expect( en => en.Prepare( null ) )
                .IgnoreArguments()
                .WhenCalled( a =>
                {
                    PreparingEnlistment e = a.Arguments.GetValue( 0 ) as PreparingEnlistment;
                    e.Prepared();
                } )
                .Repeat.Once();

            enlistmentNotification.Expect( en => en.Commit( null ) )
                .IgnoreArguments()
                .WhenCalled( a =>
                {
                    Enlistment e = a.Arguments.GetValue( 0 ) as Enlistment;
                    e.Done();
                } )
                .Repeat.Once();
        }
 internal InternalEnlistment(System.Transactions.Enlistment enlistment, IEnlistmentNotification twoPhaseNotifications, InternalTransaction transaction, System.Transactions.Transaction atomicTransaction)
 {
     this.enlistment = enlistment;
     this.twoPhaseNotifications = twoPhaseNotifications;
     this.transaction = transaction;
     this.atomicTransaction = atomicTransaction;
 }
Пример #4
0
		/// <summary>
		/// Enlists a resource manager in this transaction.
		/// </summary>
		/// <param name="p_entNotification">The resource manager to enlist.</param>
		/// <param name="p_eopOptions">The enlistment options. This value must be <see cref="EnlistmentOptions.None"/>.</param>
		/// <exception cref="ArgumentException">Thrown if <paramref name="p_eopOptions"/> is not
		/// <see cref="EnlistmentOptions.None"/>.</exception>
		public void EnlistVolatile(IEnlistmentNotification p_entResourceManager, EnlistmentOptions p_eopOptions)
		{
			if (p_eopOptions != EnlistmentOptions.None)
				throw new ArgumentException("EnlistmentOptions must be None.", "p_eopOptions");

			m_lstNotifications.Add(p_entResourceManager);
		}
        public void TestCleanup()
        {
            target = null;
            ensureTransaction = true;
            options = EnlistmentOptions.None;

            enlistmentNotification = null;
        }
 internal InternalEnlistment(System.Transactions.Enlistment enlistment, InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, ISinglePhaseNotification singlePhaseNotifications, System.Transactions.Transaction atomicTransaction)
 {
     this.enlistment = enlistment;
     this.transaction = transaction;
     this.twoPhaseNotifications = twoPhaseNotifications;
     this.singlePhaseNotifications = singlePhaseNotifications;
     this.atomicTransaction = atomicTransaction;
     this.enlistmentId = transaction.enlistmentCount++;
     this.traceIdentifier = EnlistmentTraceIdentifier.Empty;
 }
Пример #7
0
 // For Recovering Enlistments
 protected InternalEnlistment(
     Enlistment enlistment,
     IEnlistmentNotification twoPhaseNotifications
     )
 {
     Debug.Assert(this is RecoveringInternalEnlistment, "this is RecoveringInternalEnlistment");
     this.enlistment = enlistment;
     this.twoPhaseNotifications = twoPhaseNotifications;
     this.enlistmentId = 1;
     this.traceIdentifier = EnlistmentTraceIdentifier.Empty;
 }
 internal Enlistment(InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, ISinglePhaseNotification singlePhaseNotifications, Transaction atomicTransaction, EnlistmentOptions enlistmentOptions)
 {
     if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None)
     {
         this.internalEnlistment = new System.Transactions.InternalEnlistment(this, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction);
     }
     else
     {
         this.internalEnlistment = new Phase1VolatileEnlistment(this, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction);
     }
 }
Пример #9
0
 internal Enlistment(
     Guid resourceManagerIdentifier,
     InternalTransaction transaction,
     IEnlistmentNotification twoPhaseNotifications,
     ISinglePhaseNotification singlePhaseNotifications,
     Transaction atomicTransaction)
 {
     _internalEnlistment = new DurableInternalEnlistment(
         this,
         resourceManagerIdentifier,
         transaction,
         twoPhaseNotifications,
         singlePhaseNotifications,
         atomicTransaction
         );
 }
 internal override Enlistment EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
 {
     Enlistment enlistment = new Enlistment(tx, enlistmentNotification, null, atomicTransaction, enlistmentOptions);
     if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None)
     {
         base.AddVolatileEnlistment(ref tx.phase0Volatiles, enlistment);
     }
     else
     {
         base.AddVolatileEnlistment(ref tx.phase1Volatiles, enlistment);
     }
     if (DiagnosticTrace.Information)
     {
         EnlistmentTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceLtm"), enlistment.InternalEnlistment.EnlistmentTraceId, EnlistmentType.Volatile, enlistmentOptions);
     }
     return enlistment;
 }
Пример #11
0
        public static Enlistment Reenlist(
            Guid resourceManagerIdentifier,
            byte[] recoveryInformation,
            IEnlistmentNotification enlistmentNotification)
        {
            if (resourceManagerIdentifier == Guid.Empty)
            {
                throw new ArgumentException(SR.BadResourceManagerId, nameof(resourceManagerIdentifier));
            }

            ArgumentNullException.ThrowIfNull(recoveryInformation);

            ArgumentNullException.ThrowIfNull(enlistmentNotification);

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "TransactionManager.Reenlist");
                etwLog.TransactionManagerReenlist(resourceManagerIdentifier);
            }

            // Put the recovery information into a stream.
            MemoryStream stream = new MemoryStream(recoveryInformation);
            int          recoveryInformationVersion;
            string?      nodeName;

            byte[]? resourceManagerRecoveryInformation = null;

            try
            {
                BinaryReader reader = new BinaryReader(stream);
                recoveryInformationVersion = reader.ReadInt32();

                if (recoveryInformationVersion == TransactionManager.RecoveryInformationVersion1)
                {
                    nodeName = reader.ReadString();

                    resourceManagerRecoveryInformation = reader.ReadBytes(recoveryInformation.Length - checked ((int)stream.Position));
                }
                else
                {
                    if (etwLog.IsEnabled())
                    {
                        etwLog.TransactionExceptionTrace(TraceSourceType.TraceSourceBase, TransactionExceptionType.UnrecognizedRecoveryInformation, nameof(recoveryInformation), string.Empty);
                    }

                    throw new ArgumentException(SR.UnrecognizedRecoveryInformation, nameof(recoveryInformation));
                }
            }
            catch (EndOfStreamException e)
            {
                if (etwLog.IsEnabled())
                {
                    etwLog.TransactionExceptionTrace(TraceSourceType.TraceSourceBase, TransactionExceptionType.UnrecognizedRecoveryInformation, nameof(recoveryInformation), e.ToString());
                }
                throw new ArgumentException(SR.UnrecognizedRecoveryInformation, nameof(recoveryInformation), e);
            }
            catch (FormatException e)
            {
                if (etwLog.IsEnabled())
                {
                    etwLog.TransactionExceptionTrace(TraceSourceType.TraceSourceBase, TransactionExceptionType.UnrecognizedRecoveryInformation, nameof(recoveryInformation), e.ToString());
                }
                throw new ArgumentException(SR.UnrecognizedRecoveryInformation, nameof(recoveryInformation), e);
            }
            finally
            {
                stream.Dispose();
            }

            // Now ask the Transaction Manager to reenlist.
            object     syncRoot    = new object();
            Enlistment returnValue = new Enlistment(enlistmentNotification, syncRoot);

            EnlistmentState.EnlistmentStatePromoted.EnterState(returnValue.InternalEnlistment);

            returnValue.InternalEnlistment.PromotedEnlistment =
                DistributedTransactionManager.ReenlistTransaction(
                    resourceManagerIdentifier,
                    resourceManagerRecoveryInformation,
                    (RecoveringInternalEnlistment)returnValue.InternalEnlistment
                    );

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceBase, "TransactionManager.Reenlist");
            }

            return(returnValue);
        }
Пример #12
0
		private Enlistment EnlistVolatileInternal (
			IEnlistmentNotification notification,
			EnlistmentOptions options)
		{
			EnsureIncompleteCurrentScope (); 
			/* FIXME: Handle options.EnlistDuringPrepareRequired */
			Volatiles.Add (notification);

			/* FIXME: Enlistment.. ? */
			return new Enlistment ();
		}
Пример #13
0
		public Enlistment EnlistDurable (Guid manager,
			IEnlistmentNotification notification,
			EnlistmentOptions options)
		{
			throw new NotImplementedException ("DTC unsupported, only SinglePhase commit supported for durable resource managers.");
		}
 public Enlistment EnlistDurable(System.Guid resourceManagerIdentifier, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
 {
 }
 internal DurableInternalEnlistment(Enlistment enlistment, Guid resourceManagerIdentifier, InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, ISinglePhaseNotification singlePhaseNotifications, Transaction atomicTransaction) : base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction)
 {
     this.resourceManagerIdentifier = resourceManagerIdentifier;
 }
Пример #16
0
 internal DurableInternalEnlistment(
     Enlistment enlistment,
     Guid resourceManagerIdentifier,
     InternalTransaction transaction, 
     IEnlistmentNotification twoPhaseNotifications,
     ISinglePhaseNotification singlePhaseNotifications,
     Transaction atomicTransaction
     ) :
     base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction)
 {
     this.resourceManagerIdentifier = resourceManagerIdentifier;
 }
Пример #17
0
        public static Enlistment Reenlist(
            Guid resourceManagerIdentifier,
            byte[] recoveryInformation,
            IEnlistmentNotification enlistmentNotification)
        {
            if (resourceManagerIdentifier == Guid.Empty)
            {
                throw new ArgumentException(SR.BadResourceManagerId, nameof(resourceManagerIdentifier));
            }

            if (null == recoveryInformation)
            {
                throw new ArgumentNullException(nameof(recoveryInformation));
            }

            if (null == enlistmentNotification)
            {
                throw new ArgumentNullException(nameof(enlistmentNotification));
            }

            if (DiagnosticTrace.Verbose)
            {
                MethodEnteredTraceRecord.Trace(SR.TraceSourceBase, "TransactionManager.Reenlist");
            }

            if (DiagnosticTrace.Information)
            {
                ReenlistTraceRecord.Trace(SR.TraceSourceBase, resourceManagerIdentifier);
            }

            // Put the recovery information into a stream.
            MemoryStream stream = new MemoryStream(recoveryInformation);
            int          recoveryInformationVersion = 0;
            string       nodeName = null;

            byte[] resourceManagerRecoveryInformation = null;

            try
            {
                BinaryReader reader = new BinaryReader(stream);
                recoveryInformationVersion = reader.ReadInt32();

                if (recoveryInformationVersion == TransactionManager.RecoveryInformationVersion1)
                {
                    nodeName = reader.ReadString();

                    resourceManagerRecoveryInformation = reader.ReadBytes(recoveryInformation.Length - checked ((int)stream.Position));
                }
                else
                {
                    if (DiagnosticTrace.Error)
                    {
                        TransactionExceptionTraceRecord.Trace(SR.TraceSourceBase, SR.UnrecognizedRecoveryInformation);
                    }
                    throw new ArgumentException(SR.UnrecognizedRecoveryInformation, nameof(recoveryInformation));
                }
            }
            catch (EndOfStreamException e)
            {
                if (DiagnosticTrace.Error)
                {
                    TransactionExceptionTraceRecord.Trace(SR.TraceSourceBase, SR.UnrecognizedRecoveryInformation);
                }
                throw new ArgumentException(SR.UnrecognizedRecoveryInformation, nameof(recoveryInformation), e);
            }
            catch (FormatException e)
            {
                if (DiagnosticTrace.Error)
                {
                    TransactionExceptionTraceRecord.Trace(SR.TraceSourceBase, SR.UnrecognizedRecoveryInformation);
                }
                throw new ArgumentException(SR.UnrecognizedRecoveryInformation, nameof(recoveryInformation), e);
            }
            finally
            {
                stream.Dispose();
            }

            DistributedTransactionManager transactionManager = CheckTransactionManager(nodeName);

            // Now ask the Transaction Manager to reenlist.
            object     syncRoot    = new object();
            Enlistment returnValue = new Enlistment(enlistmentNotification, syncRoot);

            EnlistmentState.EnlistmentStatePromoted.EnterState(returnValue.InternalEnlistment);

            returnValue.InternalEnlistment.PromotedEnlistment =
                transactionManager.ReenlistTransaction(
                    resourceManagerIdentifier,
                    resourceManagerRecoveryInformation,
                    (RecoveringInternalEnlistment)returnValue.InternalEnlistment
                    );

            if (DiagnosticTrace.Verbose)
            {
                MethodExitedTraceRecord.Trace(SR.TraceSourceBase,
                                              "TransactionManager.Reenlist"
                                              );
            }

            return(returnValue);
        }
Пример #18
0
 public Enlistment EnlistDurable(Guid manager,
                                 IEnlistmentNotification notification,
                                 EnlistmentOptions options)
 {
     throw new NotImplementedException("DTC unsupported, only SinglePhase commit supported for durable resource managers.");
 }
 public Enlistment EnlistDurable(System.Guid resourceManagerIdentifier, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
 {
 }
Пример #20
0
 protected DurableInternalEnlistment(Enlistment enlistment, IEnlistmentNotification twoPhaseNotifications) :
     base(enlistment, twoPhaseNotifications)
 {
 }
Пример #21
0
 internal RecoveringInternalEnlistment(Enlistment enlistment, IEnlistmentNotification twoPhaseNotifications, object syncRoot) :
     base(enlistment, twoPhaseNotifications)
 {
     _syncRoot = syncRoot;
 }
Пример #22
0
 public Enlistment EnlistVolatile(
     IEnlistmentNotification notification,
     EnlistmentOptions options)
 {
     return(EnlistVolatileInternal(notification, options));
 }
Пример #23
0
 public Enlistment EnlistVolatile(
     IEnlistmentNotification enlistmentNotification,
     EnlistmentOptions enlistmentOptions)
 {
     return(EnlistVolatileInternal(enlistmentNotification, enlistmentOptions));
 }
 public Enlistment EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
 {
 }
Пример #25
0
        // Forward request to the state machine to take the appropriate action.
        //
        /// <include file='doc\Transaction' path='docs/doc[@for="Transaction.EnlistVolatile"]/*' />
        public Enlistment EnlistVolatile(
            IEnlistmentNotification enlistmentNotification,
            EnlistmentOptions enlistmentOptions
            )
        {
            if (DiagnosticTrace.Verbose)
            {
                MethodEnteredTraceRecord.Trace(SR.GetString(SR.TraceSourceLtm),
                    "Transaction.EnlistVolatile( IEnlistmentNotification )"
                    );
            }

            if (Disposed)
            {
                throw new ObjectDisposedException("Transaction");
            }

            if (enlistmentNotification == null)
            {
                throw new ArgumentNullException("enlistmentNotification");
            }

            if (enlistmentOptions != EnlistmentOptions.None && enlistmentOptions != EnlistmentOptions.EnlistDuringPrepareRequired)
            {
                throw new ArgumentOutOfRangeException("enlistmentOptions");
            }

            if (this.complete)
            {
                throw TransactionException.CreateTransactionCompletedException(SR.GetString(SR.TraceSourceLtm));
            }

            lock (this.internalTransaction)
            {
                Enlistment enlistment = this.internalTransaction.State.EnlistVolatile(this.internalTransaction,
                    enlistmentNotification, enlistmentOptions, this);

                if (DiagnosticTrace.Verbose)
                {
                    MethodExitedTraceRecord.Trace(SR.GetString(SR.TraceSourceLtm),
                        "Transaction.EnlistVolatile( IEnlistmentNotification )"
                        );
                }
                return enlistment;
            }
        }
Пример #26
0
 internal RecoveringInternalEnlistment(
     Enlistment enlistment,
     IEnlistmentNotification twoPhaseNotifications,
     object syncRoot
     ) : base(enlistment, twoPhaseNotifications)
 {
     this.syncRoot = syncRoot;
 }
Пример #27
0
 internal Enlistment(
     IEnlistmentNotification twoPhaseNotifications,
     InternalTransaction transaction,
     Transaction atomicTransaction
     )
 {
     this.internalEnlistment = new InternalEnlistment(
         this,
         twoPhaseNotifications,
         transaction,
         atomicTransaction
         );
 }
Пример #28
0
		internal PreparingEnlistment (Transaction tx, IEnlistmentNotification enlisted)
		{
			this.tx = tx;
			this.enlisted = enlisted;
			waitHandle = new ManualResetEvent (false);
		}
Пример #29
0
 protected DurableInternalEnlistment(
     Enlistment enlistment,
     IEnlistmentNotification twoPhaseNotifications
     ) : base(enlistment, twoPhaseNotifications)
 {
 }
Пример #30
0
        internal override Enlistment EnlistDurable(InternalTransaction tx, Guid resourceManagerIdentifier, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
        {
            Enlistment enlistment2;

            Monitor.Exit(tx);
            try
            {
                Enlistment enlistment = new Enlistment(resourceManagerIdentifier, tx, enlistmentNotification, null, atomicTransaction);
                EnlistmentState._EnlistmentStatePromoted.EnterState(enlistment.InternalEnlistment);
                enlistment.InternalEnlistment.PromotedEnlistment = tx.PromotedTransaction.EnlistDurable(resourceManagerIdentifier, (DurableInternalEnlistment)enlistment.InternalEnlistment, false, enlistmentOptions);
                enlistment2 = enlistment;
            }
            finally
            {
                Monitor.Enter(tx);
            }
            return(enlistment2);
        }
Пример #31
0
 public Phase1VolatileEnlistment(
     Enlistment enlistment,
     InternalTransaction transaction, 
     IEnlistmentNotification twoPhaseNotifications,
     ISinglePhaseNotification singlePhaseNotifications,
     Transaction atomicTransaction
     )
     : base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction)
 {
 }
Пример #32
0
 internal override Enlistment EnlistVolatile(
    InternalTransaction tx,
    IEnlistmentNotification enlistmentNotification,
    EnlistmentOptions enlistmentOptions,
    Transaction atomicTransaction
    )
 {
     throw TransactionException.Create(SR.TooLate, tx == null ? Guid.Empty : tx.DistributedTxId);
 }
Пример #33
0
 internal Enlistment(
     IEnlistmentNotification twoPhaseNotifications,
     object syncRoot
     )
 {
     this.internalEnlistment = new RecoveringInternalEnlistment(
         this,
         twoPhaseNotifications,
         syncRoot
         );
 }
Пример #34
0
 internal virtual Enlistment EnlistDurable(
     InternalTransaction tx,
     Guid resourceManagerIdentifier,
     IEnlistmentNotification enlistmentNotification,
     EnlistmentOptions enlistmentOptions,
     Transaction atomicTransaction
     )
 {
     throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
 }
 internal virtual Enlistment EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
 {
     throw TransactionException.CreateTransactionStateException(System.Transactions.SR.GetString("TraceSourceLtm"), tx.innerException);
 }
Пример #36
0
 internal virtual Enlistment EnlistVolatile(
     InternalTransaction tx,
     IEnlistmentNotification enlistmentNotification,
     EnlistmentOptions enlistmentOptions,
     Transaction atomicTransaction
     )
 {
     throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
 }
 public Enlistment EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
 {
 }
Пример #38
0
		internal void Rollback (Exception ex, IEnlistmentNotification enlisted)
		{
			if (aborted)
				return;

			/* See test ExplicitTransaction7 */
			if (info.Status == TransactionStatus.Committed)
				throw new TransactionException ("Transaction has already been committed. Cannot accept any new work.");

			innerException = ex;
			Enlistment e = new Enlistment ();
			foreach (IEnlistmentNotification prep in volatiles)
				if (prep != enlisted)
					prep.Rollback (e);

			if (durables.Count > 0 && durables [0] != enlisted)
				durables [0].Rollback (e);

			Aborted = true;
		}
Пример #39
0
		public Enlistment EnlistVolatile (
			IEnlistmentNotification notification,
			EnlistmentOptions options)
		{
			return EnlistVolatileInternal (notification, options);
		}
 internal override Enlistment EnlistDurable(InternalTransaction tx, Guid resourceManagerIdentifier, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
 {
     tx.promoteState.EnterState(tx);
     return tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
 }
		/// <summary>
		/// Enlists the supplied transaction manager in the current transaction.
		/// </summary>
		/// <param name="ensureTransaction">if set to <c>true</c> forces an exception if there are no available transactions.</param>
		/// <param name="enlistmentNotification">The <c>IEnlistmentNotification</c> instance to enlist in the transaction.</param>
		/// <param name="options">The transaction enlistment options.</param>
		public void EnlistInTransaction( Boolean ensureTransaction, IEnlistmentNotification enlistmentNotification, EnlistmentOptions options  )
		{
			options.EnsureIsDefined();
			if( enlistmentNotification == null )
			{
				throw new ArgumentNullException( "enlistmentNotification" );
			}

			if( ensureTransaction && Transaction.Current == null )
			{
				throw new InvalidOperationException( "Transaction is mandatory." );
			}

			if( this.EnlistedInTransaction && this.enlistedTransaction != Transaction.Current )
			{
				//Errore siamo in una transazione diversa da quella in cui ci siamo enlisted.
				throw new NotSupportedException( "Multiple Transation detected." );
			}

			if( Transaction.Current != null )
			{
				/*
				 * Dobbiamo inserirci in una Transazione:
				 *	-	ci teniamo un riferimento alla transazione in cui andiamo ad inserirci
				 *	-	chiediamo alla transazione di inserirci all'interno del suo processo
				 */
				this.enlistedTransaction = Transaction.Current;
				this.enlistedTransaction.EnlistVolatile( enlistmentNotification, options );

				/*
				 * Ci interessa tenere traccia di quando la transazione finisce
				 * per liberare un po' di risorse
				 */
				this.enlistedTransaction.TransactionCompleted += new TransactionCompletedEventHandler( OnEnlistedTransactionTransactionCompleted );

				this.OnTransactionEnlisted();
			}
		}
Пример #42
0
 public static Enlistment Reenlist(Guid manager,
                                   byte[] recoveryInfo,
                                   IEnlistmentNotification notification)
 {
     throw new NotImplementedException();
 }