Transaction Scope Similar Functionality

I want to install something very similar to a transaction scope, which creates a version on the service and removes / commits it at the end of the scope. Each SQL query executed inside a transaction scope internally scans a connection pool / transaction store to determine if it matches within the scope and responds accordingly. The subscriber does not have to transfer the transaction to every call. I am looking for this functionality.

Here is a little more about this: https://blogs.msdn.microsoft.com/florinlazar/2005/04/19/transaction-current-and-ambient-transactions/

Here is the basic one-time class:

public sealed class VersionScope : IDisposable
{
    private readonly GeodatabaseVersion _version;
    private readonly VersionManager _versionManager;

    public VersionScope(Configuration config)
    {
        _versionManager = new VersionManager(config);
        _version = _versionManager.GenerateTempVersion();
        _versionManager.Create(_version);
        _versionManager.VerifyValidVersion(_version);
        _versionManager.ServiceReconcilePull();
        _versionManager.ReconcilePull(_version);
    }

    public void Dispose()
    {
        _versionManager.Delete(_version);
    }

    public void Complete()
    {
        _versionManager.ReconcilePush(_version);
    }
}

I want all the code that I have written so far to have no idea about being in a version. I just want to enable simple

Version = GetCurrentVersionWithinScope()

.

- , .

, , . . , , , .

Edit:

:

using (var scope = new VersionScope(_config))
{
    AddFeature(); // This has no concept of scope passed to it, and could error out forcing a dispose() without a complete()
    scope.Complete();
}
+6
2

- ThreadStatic ThreadLocal . , . , , :

public class Version {
    public Version(int number) {
        Number = number;
    }
    public int Number { get; }

    public override string ToString() {
        return "Version " + Number;
    }
}

VersionScope :

public sealed class VersionScope : IDisposable {
    private bool _isCompleted;
    private bool _isDisposed;
    // note ThreadStatic attribute
    [ThreadStatic] private static Version _currentVersion;
    public static Version CurrentVersion => _currentVersion;

    public VersionScope(int version) {
        _currentVersion = new Version(version);
    }

    public void Dispose() {
        if (_isCompleted || _isDisposed)
            return;
        var v = _currentVersion;
        if (v != null) {
            DeleteVersion(v);
        }
        _currentVersion = null;
        _isDisposed = true;
    }

    public void Complete() {
        if (_isCompleted || _isDisposed)
            return;
        var v = _currentVersion;
        if (v != null) {
            PushVersion(v);
        }
        _currentVersion = null;
        _isCompleted = true;
    }

    private void DeleteVersion(Version version) {
        Console.WriteLine($"Version {version} deleted");
    }

    private void PushVersion(Version version) {
        Console.WriteLine($"Version {version} pushed");
    }
}

, , , Complete Dispose:

public sealed class VersionScope : IDisposable {
    private bool _isCompleted;
    private bool _isDisposed;
    private static readonly ThreadLocal<VersionChain> _versions = new ThreadLocal<VersionChain>();

    public static Version CurrentVersion => _versions.Value?.Current;

    public VersionScope(int version) {
        var cur = _versions.Value;
        // remember previous versions if any
        _versions.Value = new VersionChain(new Version(version), cur);
    }

    public void Dispose() {
        if (_isCompleted || _isDisposed)
            return;
        var cur = _versions.Value;
        if (cur != null) {
            DeleteVersion(cur.Current);
            // restore previous
            _versions.Value = cur.Previous;
        }
        _isDisposed = true;
    }

    public void Complete() {
        if (_isCompleted || _isDisposed)
            return;
        var cur = _versions.Value;
        if (cur != null) {
            PushVersion(cur.Current);
            // restore previous
            _versions.Value = cur.Previous;
        }
        _isCompleted = true;
    }

    private void DeleteVersion(Version version) {
        Console.WriteLine($"Version {version} deleted");
    }

    private void PushVersion(Version version) {
        Console.WriteLine($"Version {version} pushed");
    }

    // just a class to store previous versions
    private class VersionChain {
        public VersionChain(Version current, VersionChain previous) {
            Current = current;
            Previous = previous;
        }

        public Version Current { get; }
        public VersionChain Previous { get; }
    }
}

, . ( , , - ):

static void Main(string[] args) {
    PrintCurrentVersion(); // no version
    using (var s1 = new VersionScope(1)) {
        PrintCurrentVersion(); // version 1
        s1.Complete();
        PrintCurrentVersion(); // no version, 1 is already completed
        using (var s2 = new VersionScope(2)) {
            using (var s3 = new VersionScope(3)) {
                PrintCurrentVersion(); // version 3
            } // version 3 deleted
            PrintCurrentVersion(); // back to version 2
            s2.Complete();
        }
        PrintCurrentVersion(); // no version, all completed or deleted
    }
    Console.ReadKey();
}

private static void PrintCurrentVersion() {
    Console.WriteLine("Current version: " + VersionScope.CurrentVersion);
}

, , ThreadLocal , async . AsyncLocal, . , VersionScope, , . - TransactionScopeAsyncFlowOption, TransactionScope, , .

:

public sealed class VersionScope : IDisposable {
    private bool _isCompleted;
    private bool _isDisposed;
    private readonly bool _asyncFlow;
    // thread local versions
    private static readonly ThreadLocal<VersionChain> _tlVersions = new ThreadLocal<VersionChain>();
    // async local versions
    private static readonly AsyncLocal<VersionChain> _alVersions = new AsyncLocal<VersionChain>();
    // to get current version, first check async local storage, then thread local
    public static Version CurrentVersion => _alVersions.Value?.Current ?? _tlVersions.Value?.Current;
    // helper method
    private VersionChain CurrentVersionChain => _asyncFlow ? _alVersions.Value : _tlVersions.Value;

    public VersionScope(int version, bool asyncFlow = false) {
        _asyncFlow = asyncFlow;

        var cur = CurrentVersionChain;
        // remember previous versions if any
        if (asyncFlow) {
            _alVersions.Value = new VersionChain(new Version(version), cur);
        }
        else {
            _tlVersions.Value = new VersionChain(new Version(version), cur);
        }
    }

    public void Dispose() {
        if (_isCompleted || _isDisposed)
            return;
        var cur = CurrentVersionChain;
        if (cur != null) {
            DeleteVersion(cur.Current);
            // restore previous
            if (_asyncFlow) {
                _alVersions.Value = cur.Previous;
            }
            else {
                _tlVersions.Value = cur.Previous;
            }
        }
        _isDisposed = true;
    }

    public void Complete() {
        if (_isCompleted || _isDisposed)
            return;
        var cur = CurrentVersionChain;
        if (cur != null) {
            PushVersion(cur.Current);
            // restore previous
            if (_asyncFlow) {
                _alVersions.Value = cur.Previous;
            }
            else {
                _tlVersions.Value = cur.Previous;
            }
        }
        _isCompleted = true;
    }

    private void DeleteVersion(Version version) {
        Console.WriteLine($"Version {version} deleted");
    }

    private void PushVersion(Version version) {
        Console.WriteLine($"Version {version} pushed");
    }

    // just a class to store previous versions
    private class VersionChain {
        public VersionChain(Version current, VersionChain previous) {
            Current = current;
            Previous = previous;
        }

        public Version Current { get; }
        public VersionChain Previous { get; }
    }
}

:

static void Main(string[] args) {
    Test();
    Console.ReadKey();
}

static async void Test() {
    PrintCurrentVersion(); // no version
    using (var s1 = new VersionScope(1, asyncFlow: true)) {
        await Task.Delay(100);
        PrintCurrentVersion(); // version 1
        await Task.Delay(100);
        s1.Complete();
        await Task.Delay(100);
        PrintCurrentVersion(); // no version, 1 is already completed
        using (var s2 = new VersionScope(2, asyncFlow: true)) {
            using (var s3 = new VersionScope(3, asyncFlow: true)) {
                PrintCurrentVersion(); // version 3
            } // version 3 deleted
            await Task.Delay(100);
            PrintCurrentVersion(); // back to version 2
            s2.Complete();
        }
        await Task.Delay(100);
        PrintCurrentVersion(); // no version, all completed or deleted
    }
}

private static void PrintCurrentVersion() {
    Console.WriteLine("Current version: " + VersionScope.CurrentVersion);
}
+1

IDisposable, , . (. IDisposable "" " " ?)

. , :

class LevelContext
{
    private int _level;

    public int CurrentLevel
    {
        get { return _level; }
        set { _level = value < 0 ? 0 : value; }
    }

    public ILevel NewLevel(int depth = 1)
    {
        return new Level(this, depth);
    }

    /// <summary>
    /// Provides an interface that calling code can use to handle level objects.
    /// </summary>
    public interface ILevel : IDisposable
    {
        LevelContext Owner { get; }
        int Depth { get; }
        void Close();
    }

    /// <summary>
    /// Private class that provides an easy way to scope levels by allowing
    /// them to participate in the "using" construct. Creation of a Level results in an
    /// increase in owner level, while disposal returns owner level to what it was before.
    /// </summary>
    class Level : ILevel
    {
        public Level(LevelContext owner, int depth)
        {
            Owner = owner;
            Depth = depth;
            PreviousLevel = owner.CurrentLevel;
            Owner.CurrentLevel += Depth;
        }

        public LevelContext Owner { get; private set; }
        public int Depth { get; private set; }
        public int PreviousLevel { get; private set; }

        public void Close()
        {
            if (Owner != null)
            {
                Owner.CurrentLevel = PreviousLevel;
                Owner = null;
            }
        }

        void IDisposable.Dispose()
        {
            Close();
        }

    }

:

    static void Main(string[] args)
    {
        var lc = new LevelContext();

        Console.WriteLine(lc.CurrentLevel);

        using (lc.NewLevel())
            Console.WriteLine(lc.CurrentLevel);

        Console.WriteLine(lc.CurrentLevel);
    }

, - -, . - VersionScopes.

0

All Articles