---
title: "How to handle Transaction in .NET Core?"  
description: "How to handle Transaction in .NET Core?"  
author: "Ravi Vishwakarma"  
published: 2026-03-16  
updated: 2026-04-20  
canonical: https://answers.mindstick.com/qa/116422/how-to-handle-transaction-in-dot-net-core  
category: "asp.net"  
tags: ["asp.net"]  
reading_time: 3 minutes  

---

# How to handle Transaction in .NET Core?

## Answers

### Answer by Anubhav Sharma

Handling [transactions](https://www.mindstick.com/forum/34047/how-to-use-transactions-sql-server) in .NET Core (especially with [Entity Framework](https://www.mindstick.com/articles/12153/how-to-access-data-in-mvc-using-entity-framework) Core) is straightforward once you understand when to rely on automatic behavior and when to take manual control.

![How to handle Transaction in .NET Core?](https://answers.mindstick.com/questionanswer/be164334-3cc0-4537-b9b6-c5f25fc2ed70/images/927bfd76-6f6a-43e5-8f60-210c16636578.png)

## 1. Default Behavior (Auto Transactions)

When you call:

```cs
await dbContext.SaveChangesAsync();
```

Entity [Framework Core](https://www.mindstick.com/forum/159842/how-to-read-record-from-database-in-asp-mvc-core-using-entity-framework-core-1-0) automatically wraps **all changes in a transaction**.

### Example

```cs
using (var context = new AppDbContext())
{
    context.Users.Add(new User { Name = "A" });
    context.Orders.Add(new Order { Amount = 100 });

    await context.SaveChangesAsync(); // Auto transaction
}
```

- If anything fails → everything rolls back
- If success → everything commits

Use this for **simple CRUD operations**

## 2. Manual Transaction (Full Control)

Use this when:

- Multiple `SaveChanges()` calls
- Cross-service logic
- Complex [business operations](https://www.mindstick.com/blog/306817/how-microsoft-platforms-are-transforming-everyday-business-operations)

### Example

```cs
using (var context = new AppDbContext())
{
    using (var transaction = await context.Database.BeginTransactionAsync())
    {
        try
        {
            context.Users.Add(new User { Name = "A" });
            await context.SaveChangesAsync();

            context.Orders.Add(new Order { Amount = 100 });
            await context.SaveChangesAsync();

            await transaction.CommitAsync();
        }
        catch (Exception)
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
}
```

- Gives you **fine-grained control**
- Useful for multi-step operations

## 3. Using TransactionScope (Cross-Context / Distributed)

Use `TransactionScope` when:

- Multiple DB contexts
- Multiple databases
- External services involved

### Example

```cs
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
    using (var context1 = new AppDbContext())
    {
        context1.Users.Add(new User { Name = "A" });
        await context1.SaveChangesAsync();
    }

    using (var context2 = new AppDbContext())
    {
        context2.Orders.Add(new Order { Amount = 200 });
        await context2.SaveChangesAsync();
    }

    scope.Complete();
}
```

Important:

- Requires `TransactionScopeAsyncFlowOption.Enabled` for async
- Can escalate to **distributed transaction (MSDTC)** → expensive

## 4. Handling Isolation Levels

You can control concurrency behavior:

```cs
using (var transaction = await context.Database.BeginTransactionAsync(
    System.Data.IsolationLevel.Serializable))
{
    // Your logic
}
```

### Common Levels

- `ReadCommitted` (default) → safe + fast
- `RepeatableRead` → prevents re-reading changes
- `Serializable` → strictest (but slowest)

## 5. Best Practices (Production Level)

### Keep transactions short

- Avoid long-running operations inside transactions.

### Avoid external API calls inside transaction

Bad:

```cs
await transaction.BeginAsync();
await CallExternalAPI(); // risky
```

### Use retry policies

Combine with:

- Polly
- [EF Core](https://www.mindstick.com/interview/34146/how-do-you-perform-migrations-in-ef-core) execution strategies

### Use one DbContext per transaction

- DbContext is **NOT thread-safe**

## 6. Advanced Pattern (Execution Strategy + Transaction)

For resilient systems (like SQL Azure):

```cs
var strategy = context.Database.CreateExecutionStrategy();

await strategy.ExecuteAsync(async () =>
{
    using (var transaction = await context.Database.BeginTransactionAsync())
    {
        try
        {
            context.Users.Add(new User { Name = "RetryUser" });
            await context.SaveChangesAsync();

            await transaction.CommitAsync();
        }
        catch
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
});
```

## 7. When to Use What?

| Scenario | Approach |
| --- | --- |
| Simple insert/update | Auto transaction |
| Multiple SaveChanges | Manual transaction |
| Multiple DB / services | TransactionScope |
| Cloud + retry needed | ExecutionStrategy |

## Final Insight

- 80% cases → **SaveChanges() is enough**
- 15% → Manual transaction
- 5% → Distributed transactions


---

Original Source: https://answers.mindstick.com/qa/116422/how-to-handle-transaction-in-dot-net-core

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
