7

I am using EF 6 with a UoW pattern. I have multiple contexts defined in my UoW since I'm using data from multiple databases. Everything seems to be working correctly except the CommitAsync function I have defined. Here's the code I have:

    public async Task CommitAsync()
    {
        try
        {
            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                if (_context1 != null)
                    await _context1.SaveChangesAsync();
                if (_context2 != null)
                    await _context2.SaveChangesAsync();

                scope.Complete();
            }
        }
        catch (DbEntityValidationException ex)
        {
            //..
        }
    }

When I run this code saving changes in both contexts I get:

The transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D024)

The await _context2.SaveChangesAsync(); is where the error happens. If I remove the TransactionScope from this function, the code seems to work without error. I am hesitant to remove the scope for multiple contexts.

Just in case it'll help, here's the code I use to call this function:

        state.Name = "Texas";
        _uow.StateRepository.Update(state);

        user.FirstName = "John";
        _uow.UserRepository.Update(user);

        await _uow.CommitAsync();

Thanks!

11
  • 1
    There's nothing wrong with the code it is the config on the box running the code msdtc has got remote/network transactions disabled. Commented Aug 14, 2015 at 14:32
  • Why do you want to use the TransactionScope? If the save fails it will be undone anyway. Using TransactionScope just leads to possible deadlocks.
    – Jamie Rees
    Commented Aug 14, 2015 at 14:32
  • 2
    @JamieRees I suspect the OP wants either both updates to work or both to fail and avoid a situation where one worked but one failed. Commented Aug 14, 2015 at 14:34
  • Yeah that would make sense!
    – Jamie Rees
    Commented Aug 14, 2015 at 14:34
  • 2
    Are you aware that this requires distributed transactions? Main problem is that they do not work with many HA solutions. Problem 2 is performance.
    – usr
    Commented Aug 14, 2015 at 14:37

1 Answer 1

3

Using two connections in the same scope requires MSDTC.

You can enable MSDTC to solve this problem. But it does not work with many HA solutions and is slow.

The only way to avoid using MSDTC is to use the same connection for everything that must be transacted. Since you are using multiple databases that is harder than usual. You need to use SqlConnection.ChangeDatabase or issue the respective SQL to switch between databases on the same connection. The connection must be kept open.

Alternatively, you can use three part names for your object references (e.g. DB1.dbo.MyTable).

There is no other way. Either MSDTC or sharing of the same connection.

5
  • thank you for your help. I suppose another option is just to remove the scope, but be left with the possibility of the above posted by Ben. I suppose that wouldn't be terrible in my situation since the data being saved in the different databases isn't really related. Commented Aug 14, 2015 at 16:56
  • @AaronSanders if you like debugging inconsistent data... This will happen. Timeout can happen at any time.
    – usr
    Commented Aug 14, 2015 at 17:04
  • @AaronSanders additional reading for you "Two Generals Problem". This is the thought experiment that describes how FRIGGIN hard distributed transactions are.
    – Aron
    Commented Aug 14, 2015 at 19:12
  • @Aron good point, and most people don't know that it's impossible to have 100% reliable distributed transactions. Strangely, this is never mentioned in the product documentations...
    – usr
    Commented Aug 14, 2015 at 19:33
  • @usr I assume that most people expect software to obey to laws of mathematics/physics.
    – Aron
    Commented Aug 14, 2015 at 19:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.