File: System\Transactions\DtcProxyShim\ResourceManagerShim.cs
Web Access
Project: src\src\runtime\src\libraries\System.Transactions.Local\src\System.Transactions.Local.csproj (System.Transactions.Local)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;
using System.Transactions.DtcProxyShim.DtcInterfaces;
using System.Transactions.Oletx;

namespace System.Transactions.DtcProxyShim;

internal sealed class ResourceManagerShim
{
    private readonly DtcProxyShimFactory _shimFactory;

    internal ResourceManagerShim(DtcProxyShimFactory shimFactory)
        => _shimFactory = shimFactory;

    public IResourceManager? ResourceManager { get; set; }

    public void Enlist(
        TransactionShim transactionShim,
        OletxEnlistment managedIdentifier,
        out EnlistmentShim enlistmentShim)
    {
        var pEnlistmentNotifyShim = new EnlistmentNotifyShim(_shimFactory, managedIdentifier);
        var pEnlistmentShim = new EnlistmentShim(pEnlistmentNotifyShim);

        ITransaction transaction = transactionShim.Transaction;
        ResourceManager!.Enlist(transaction, pEnlistmentNotifyShim, out Guid txUow, out OletxTransactionIsolationLevel isoLevel, out ITransactionEnlistmentAsync pEnlistmentAsync);

        pEnlistmentNotifyShim.EnlistmentAsync = pEnlistmentAsync;
        pEnlistmentShim.EnlistmentAsync = pEnlistmentAsync;

        enlistmentShim = pEnlistmentShim;
    }

    public void Reenlist(byte[] prepareInfo, out OletxTransactionOutcome outcome)
    {
        // Call Reenlist on the proxy, waiting for 5 milliseconds for it to get the outcome.  If it doesn't know that outcome in that
        // amount of time, tell the caller we don't know the outcome yet.  The managed code will reschedule the check by using the
        // ReenlistThread.
        try
        {
            ResourceManager!.Reenlist(prepareInfo, (uint)prepareInfo.Length, 5, out OletxXactStat xactStatus);
            outcome = xactStatus switch
            {
                OletxXactStat.XACTSTAT_ABORTED => OletxTransactionOutcome.Aborted,
                OletxXactStat.XACTSTAT_COMMITTED => OletxTransactionOutcome.Committed,
                _ => OletxTransactionOutcome.Aborted
            };
        }
        catch (COMException e) when (e.ErrorCode == OletxHelper.XACT_E_REENLISTTIMEOUT)
        {
            outcome = OletxTransactionOutcome.NotKnownYet;
            return;
        }
    }

    public void ReenlistComplete()
        => ResourceManager!.ReenlistmentComplete();
}