21

I want to have a transaction for copying a file and then inserting a record in database. something like below statement, but transaction doesn't cover copying file. What's the solution?

using (TransactionScope scope1 = new TransactionScope())
{
    // Copy a file
    fileMgr.Move(srcFileName, destFileName);

    // Insert a database record
    dbMgr.ExecuteNonQuery(insertSql);

    scope1.Complete();
}
Raymond Morphy
  • 2,464
  • 9
  • 51
  • 93

4 Answers4

19

Try to use .NET Transactional File Manager

This library allows you to wrap file system operations in transactions like this:

// Wrap a file copy and a database insert in the same transaction
TxFileManager fileMgr = new TxFileManager();
using (TransactionScope scope1 = new TransactionScope())
{
    // Copy a file
    fileMgr.Copy(srcFileName, destFileName);

    // Insert a database record
    dbMgr.ExecuteNonQuery(insertSql);

    scope1.Complete();
} 
dmtweigt
  • 83
  • 4
Damith
  • 62,401
  • 13
  • 102
  • 153
  • 18
    This library **is NOT** a wrapper of Transactional NTFS. It simply implements `IEnlistmentNotification` and allow manual standard file operations to work with `TransactionScope`. For instance, to enable rollback for a write operation on an existing file, it first creates a backup of the file that will be written, then writes to the backuped file, and finally replaces the initial file with the backuped/modified file if the transaction is committed, or deletes the backup file if the transaction is rollbacked. This has **nothing** to do with Transactional NTFS. – ken2k May 21 '12 at 13:01
  • Also do note that the author of the lib is pretty clear about that. I you want to use Transactional NTFS in .Net, see http://archive.msdn.microsoft.com/txfmanaged. – ken2k May 21 '12 at 13:05
  • 2
    I was wary of this, since updates are scarce, but seeing as TxF is off the menu (see my comment to xanatos), this seems like the best solution (for me). – CJM Aug 15 '12 at 09:44
  • How can I create I new File with that lib? I have only the byte[] and need to create that file within the transaction. – Junior Sep 23 '15 at 18:57
  • Thanks, @Damith. I threw this comment on a dupe question's answer too: The github and nuget versions of the Tx File Manager library are different: the github one includes `File.WriteAllBytes` and the nuget one doesn't. You can get the github version here: https://github.com/rsevil/Transactions – Alex Jan 04 '19 at 13:44
5

Newer versions of Windows have something called TxF (Transactional NTFS) you can use. Here there is an example of code: WINDOWS VISTA - INTRODUCING TXF IN C# (PART 2) - USING SYSTEM.TRANSACTIONS AND THE DTC (I'm sorry for the caps lock on, but the title of the page is that :-) )

You'll have to use MoveFileTransacted instead of DeleteFileTransactioned. Once you are in a DTC, your SQL connection should be enrolled into it and so everything should be a single big transaction.

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • @DavidePiras Scrap that... It's TxR (the Transactioned Registry) that is incompatible with SQL. Yes, it should work. – xanatos Oct 29 '11 at 14:15
  • See http://stackoverflow.com/a/2289410/870604 for a .Net wrapper of TxF. Very simple actually, could be easily integrated in a project. – ken2k May 21 '12 at 13:03
  • 3
    MS are warning against using TxF since it is likely to be removed from future OS's: http://msdn.microsoft.com/en-us/library/windows/desktop/hh802690(v=vs.85).aspx. Certain TxF features are already being deprecated in Windows 8: http://xpwasmyidea.blogspot.co.uk/2011/09/features-removed-in-windows-8.html – CJM Aug 15 '12 at 09:42
  • Though fine at the time, it is now perhaps out of date. _[Microsoft strongly recommends developers utilize alternative means to achieve your application’s needs. Many scenarios that TxF was developed for can be achieved through simpler and more readily available techniques. Furthermore, TxF may not be available in future versions of Microsoft Windows](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365241(v=vs.85).aspx)_ –  Mar 12 '15 at 10:53
  • @MickyDuncan Yes, sadly the TxF is a technology that has entered a death spiral :-( – xanatos Mar 12 '15 at 10:54
0

Please read up on this article before using transactional NTFS or any other suggestions: https://learn.microsoft.com/nl-nl/windows/desktop/FileIO/deprecation-of-txf

TxF is a complex and nuanced set of APIs which are not commonly used by 3rd party applications. With the possibility that these APIs may not be available in future versions of Windows, and the fact that there are simpler alternative means to achieve many of the scenarios which TxF was developed for, Microsoft strongly recommends developers to investigate those alternative means instead of creating a dependency on TxF in their applications.

A better way to achieve ACID, is to use Filestream storage

Ozkan
  • 3,880
  • 9
  • 47
  • 78
-1

you could manually roll your own file transaction, if the commit fails, move the file back to it's original location

using (TransactionScope scope1 = new TransactionScope())
{
    // Copy a file
    fileMgr.Move(srcFileName, destFileName);

    try
    {
        // Insert a database record
        dbMgr.ExecuteNonQuery(insertSql);

        scope1.Complete();
    } catch (Exception) {
        fileMgr.Move(destFileName, srcFileName);
    }
}

i'm not 100% on the syntax for determining if an error occurred committing the transaction, but i think this illustrates the concept

xanatos
  • 109,618
  • 12
  • 197
  • 280
Jason
  • 15,915
  • 3
  • 48
  • 72
  • You should move the `ExeuteNonQuery` INSIDE the `try` – xanatos Oct 29 '11 at 14:24
  • This does not guarantee restoration of initial state when failing. The destFileName could be filled by another file, for instance. – mafu Mar 30 '20 at 04:02