1

I am trying to add a middleware so that transaction begins at the beginning of the request and commits or rollbacks depending on the situation. This is my middleware:

    public class TransactionPerRequestMiddleware
    {
      private readonly RequestDelegate next_;

      public TransactionPerRequestMiddleware(RequestDelegate next)
      {
        next_ = next;
      }

      public async Task Invoke(HttpContext context, AppDbContext dbContext)
       {
        var is_everything_ok = true;
        var transaction = dbContext.Database.BeginTransaction(
            System.Data.IsolationLevel.ReadCommitted);
        if (context.Response.StatusCode != 200 && is_everything_ok)
        {
            is_everything_ok = false;
        }

        await next_.Invoke(context);

        if ((context.Response.StatusCode == 200 || 
         context.Response.StatusCode == 302) && is_everything_ok)
        {
            transaction.Commit();
        }
        else
        {
            transaction.Rollback();
        }
      }
    }

I registered the above middleware in Startup.cs

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
      app.UseMiddleware<TransactionPerRequestMiddleware>();
    }

I have a method in service which performs two database operations one after another.

    public void method()
    {
      databaseOperation1();
      databaseOperation2();
    }

If exception occurs in databaseOperation2() , databaseOperation1() is not rolling back currently. I am trying to implement Unit Of Work for each web request.

Thanks in advance.

Dot Net developer
  • 436
  • 1
  • 5
  • 19
  • 1
    Transaction per request means *business* transaction per request, *not* database transaction per request. Database transaction per request is a great way to eradicate performance and throughput by causing requests to block each other. The `SaveChanges` method of a DbContext uses a transaction internally which means you *don't* need explicit transactions if you work through the ORM. It has nothing to do with UoW either - the context contains all the changes made in a UoW and persists them when `SaveChanges` is called. If you don't want them persisted, don't call SaveChanges – Panagiotis Kanavos Jan 04 '19 at 09:12
  • As for why this code fails, 1) if `method()` doesn't receive the generated context but works with a *different* context instance, it isn't affected by any transaction created on the original context 2) the proper way to handle transactions is to use a `using` block that *ensures* they are rolled back even if an error occurs. The way `Invoke` is written nothing will be called in case of exception and the transaction will remain *active* and *blocking* resources until it's garbage-collected. – Panagiotis Kanavos Jan 04 '19 at 09:19
  • @PanagiotisKanavos sir how can I manage UoW in EF core? Pomelo MySQL provider doesnot work well with TransactionScope. – Dot Net developer Jan 04 '19 at 09:37
  • 1
    `TransactionScope` is used to implement explicit database transactions. As I said, UoW has nothing to do with database transactions. When you use a context, all changes are persisted the moment you call `SaveChanges`. If you delay calling SaveChanges until the very end, you don't need an explicit transaction. `SaveChanges` uses a transaction internally so there's no chance of partial changes if something goes wrong. – Panagiotis Kanavos Jan 04 '19 at 09:44
  • The only other benefit (and huge drawback) from using an explicit transaction is *preventing other requests* from modifying data until you commit. That's why a database transaction per request is so bad for performance and why optimistic concurrency is used instead. None of these has to do with Unit of Work though, those are concurrency mechanisms. – Panagiotis Kanavos Jan 04 '19 at 09:47

0 Answers0