English | 简体中文
client-csharp is the C# client of Distributed Transaction Manager DTM.
| client | features | nuget | 
|---|---|---|
| dtmcli | saga/tcc/2-phase message | |
| dtmgrpc | saga/tcc/2-phase message | |
| workflow | - | - | 
DTM is a distributed transaction solution which provides cross-service eventually data consistency. It provides saga, tcc, xa, 2-phase message strategies for a variety of application scenarios. It also supports multiple languages and multiple store engine to form up a transaction as following:
- 
Extremely easy to adapt - Support HTTP and gRPC, provide easy-to-use programming interfaces, lower substantially the barrier of getting started with distributed transactions. Newcomers can adapt quickly.
 
- 
Easy to use - Relieving developers from worrying about suspension, null compensation, idempotent transaction, and other tricky problems, the framework layer handles them all.
 
- 
Language-agnostic - Suit for companies with multiple-language stacks. Easy to write bindings for Go, Python, PHP, Node.js, Ruby, and other languages.
 
- 
Easy to deploy, easy to extend - DTM depends only on MySQL, easy to deploy, cluster, and scale horizontally.
 
- 
Support for multiple distributed transaction protocol - TCC, SAGA, XA, Transactional messages.
 
There is no mature open-source distributed transaction framework for non-Java languages. Mature open-source distributed transaction frameworks for Java language include Ali's Seata, Huawei's ServiceComb-Pack, Jingdong's shardingsphere, himly, tcc-transaction, ByteTCC, and so on, of which Seata is most widely used.
The following is a comparison of the main features of dtm and Seata.
| Features | DTM | Seata | Remarks | 
|---|---|---|---|
| Supported languages | Golang, C#, Java, Python, PHP, and others | Java | dtm allows easy access from a new language | 
| Exception handling | Sub-transaction barrier | manual | dtm solves idempotent transaction, hanging, null compensation | 
| TCC | ✓ | ✓ | |
| XA | ✓ | ✓ | |
| AT | suggest XA | ✓ | AT is similar to XA with better performance but with dirty rollback | 
| SAGA | support concurrency | complicated state-machine mode | dtm's state-machine mode is being planned | 
| Transactional Messaging | ✓ | ✗ | dtm provides Transactional Messaging similar to RocketMQ | 
| Multiple DBs in a service | ✓ | ✗ | |
| Communication protocols | HTTP, gRPC | Dubbo, no HTTP | |
| Star count | dtm 0.1 is released from 20210604 and under fast development | 
From the features' comparison above, if your language stack includes languages other than Java, then dtm is the one for you. If your language stack is Java, you can also choose to access dtm and use sub-transaction barrier technology to simplify your business development.
Add nuget package via the following command
dotnet add package DtmcliThere are two ways to configure
- Configure with setup action
services.AddDtmcli(x =>
{
    // DTM server HTTP address
    x.DtmUrl = "http://localhost:36789";
    
    // request timeout for DTM server, unit is milliseconds
    x.DtmTimeout = 10000; 
    
    // request timeout for trans branch, unit is milliseconds
    x.BranchTimeout = 10000;
    
    // barrier database type, mysql, postgres, sqlserver
    x.SqlDbType = "mysql";
    // barrier table name
    x.BarrierTableName = "dtm_barrier.barrier";
});- Configure with IConfiguration
services.AddDtmcli(Configuration, "dtm");And the configuration file
{
  "dtm": {
    "DtmUrl": "http://localhost:36789",
    "DtmTimeout": 10000,
    "BranchTimeout": 10000,
    "SqlDbType": "mysql",
    "BarrierTableName": "dtm_barrier.barrier",
  }
}public class MyBusi
{ 
    private readonly Dtmcli.IDtmTransFactory _transFactory;
    public MyBusi(Dtmcli.IDtmTransFactory transFactory)
    {
        this._transFactory = transFactory;
    }
    public async Task DoBusAsync()
    {
        var gid = Guid.NewGuid().ToString();
        var req = new BusiReq {  Amount = 30 };
        
        // NOTE: After DTM v1.12.2
        // when svc start with http or https, DTM server will send HTTP request to svc
        // when svc don't start with http or https,  DTM server will send gRPC request to svc
        var svc = "http://localhost:5005";
        var saga = _transFactory.NewSaga(gid);
        // Add sub-transaction
        saga.Add(
            // URL of forward action 
            svc + "/api/TransOut",
            
            // URL of compensating action
            svc + "/api/TransOutCompensate",
            // Arguments of actions
            req);
        saga.Add(
            svc + "/api/TransIn",
            svc + "/api/TransInCompensate",
            req);
        await saga.Submit();
    }
}public class MyBusi
{ 
    private readonly Dtmcli.TccGlobalTransaction _globalTransaction;
    public MyBusi(Dtmcli.TccGlobalTransaction globalTransaction)
    {
        this._globalTransaction = globalTransaction;
    }
    public async Task DoBusAsync()
    {
        var gid = Guid.NewGuid().ToString();
        var req = new BusiReq {  Amount = 30 };
        var svc = "http://localhost:5005";
        await _globalTransaction.Excecute(gid, async tcc =>
        {
            // Create tcc sub-transaction
            await tcc.CallBranch(
                // Arguments of stages
                req,
                // URL of Try stage
                svc + "/api/TransOutTry",
                // URL of Confirm stage
                svc + "/api/TransOutConfirm",
                 // URL of Cancel stage
                svc + "/api/TransOutCancel");
            await tcc.CallBranch(
                req,
                svc + "/api/TransInTry",
                svc + "/api/TransInConfirm",
                svc + "/api/TransInCancel");
        });
    }
}public class MyBusi
{ 
    private readonly Dtmcli.IDtmTransFactory _transFactory;
    public MyBusi(Dtmcli.IDtmTransFactory transFactory)
    {
        this._transFactory = transFactory;
    }
    public async Task DoBusAsync()
    {
        var gid = Guid.NewGuid().ToString();
        var req = new BusiReq {  Amount = 30 };
        var svc = "http://localhost:5005";
        var msg = _transFactory.NewMsg(gid);
        // Add sub-transaction
        msg.Add(
            // URL of action 
            svc + "/api/TransOut",
            // Arguments of action
            req);
        msg.Add(
            svc + "/api/TransIn",
            req);
        // Usage 1:
        // Send prepare message 
        await msg.Prepare(svc + "/api/QueryPrepared");
        // Send submit message
        await msg.Submit();
        // Usage 2:
        using (var conn = GetDbConnection())
        {
            await msg.DoAndSubmitDB(svc + "/api/QueryPrepared", conn, async tx => 
            {
                await conn.ExecuteAsync("insert ....", new { }, tx);
                await conn.ExecuteAsync("update ....", new { }, tx);
                await conn.ExecuteAsync("delete ....", new { }, tx);
            });
        }
    }
}public class MyBusi
{ 
    private readonly Dtmcli.XaGlobalTransaction _globalTransaction;
    public MyBusi(Dtmcli.XaGlobalTransaction globalTransaction)
    {
        this._globalTransaction = globalTransaction;
    }
    public async Task DoBusAsync(CancellationToken cancellationToken)
    {
        var svc = "http://localhost:5005";
        await _globalTransaction.ExcecuteAsync(async (Xa xa) =>
        {
            // NOTE: Limitations of using Xa mode
            // The current mode only supports mysql, postgresDB, please modify the corresponding client configuration, such as SqlDbType, etc.
            // Connection pooling needs to be turned off for mysql versions below 8.0
            // Create XA sub-transaction
            await xa.CallBranch(
                // Arguments of action
                new TransRequest("1", -30), 
                // URL of action 
                svc + "/XaTransOut",
                // Cancel token
                cancellationToken);
            
            await xa.CallBranch(
                new TransRequest("2", 30), 
                svc + "/XaTransIn", 
                cancellationToken);
        }, cancellationToken);
    }
}Refer to https://github.com/dtm-labs/dtmcli-csharp-sample client-csharp/samples · dtm-labs/client-csharp
Add wechat friend with id yedf2008, or scan the OR code. Fill in csharp as verification.

