Click or drag to resize

Editing files

A class derived from EditFileManager must implement method OnCommit to state how the managed file should be edited.

In the following example, a file manager edits a document in XML format in case of a successfully committed transaction.

C#
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Xml;
using System.Xml.Linq;

namespace Novacta.Transactions.IO.CodeExamples
{
    /// <summary>
    /// Edits a file containing an XML document.
    /// </summary>
    public class EditXmlFileManager : EditFileManager
    {
        /// <summary>
        /// Initializes a new instance of the 
        /// <see cref="EditXmlFileManager"/> class.
        /// </summary>
        /// <param name="path">The path of the managed file.</param>
        public EditXmlFileManager(
            string path) : base(path)
        {
        }

        /// <summary>
        /// Called when the transaction is successfully committed.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method looks for an <c>items</c> node and, 
        /// if found, add a child <c>item</c> node having 
        /// <c>0002</c> as its <c>id</c> and 
        /// <c>A new item</c> as its <c>description</c>. 
        /// </para>
        /// </remarks>
        protected override void OnCommit()
        {
            var document = XDocument.Load(this.ManagedFileStream);

            var items = from node in document.Descendants()
                        where node.Name == "items"
                        select node;

            var itemsNode = items.FirstOrDefault();

            if (itemsNode != null)
            {
                XElement newItem = new XElement("item",
                    new XElement("id", "0002"),
                    new XElement("description", "A new item"));
                itemsNode.Add(newItem);
            }

            // Truncate the stream to delete the old content.
            this.ManagedFileStream.SetLength(0);

            var xmlTextWriter = new XmlTextWriter(this.ManagedFileStream, Encoding.UTF8);
            xmlTextWriter.Formatting = Formatting.Indented;
            document.Save(this.ManagedFileStream);
        }
    }

    public class EditFileManagerExample0  
    {
        public void Main()
        {
            // Define the XML document to be edited in case 
            // of a successfully committed transaction.
            var document = new XDocument();
            string content =
                "<?xml version='1.0' encoding='utf-8'?>" +
                "<items>" +
                    "<item>" +
                    "<id>0001</id>" +
                    "<description>A mysterious item</description>" +
                    "</item>" +
                "</items>";
            document = XDocument.Parse(content);

            // Define the path for the file where 
            // the document is saved.
            var managedPath = "edit-file-0.xml";

            // Save the document in a file. 
            // This will be edited in case of a 
            // successfully committed transaction.
            using (FileStream stream =
                new FileStream(managedPath, FileMode.Create))
            {
                document.Save(stream, SaveOptions.None);
            }

            // Create the manager.
            var manager = new EditXmlFileManager(managedPath);

            bool transactionSuccessfullyCommitted = true;

            try
            {
                // Create a TransactionScope to manage 
                // your resources, such as files or database
                // connections. In this way, it is guaranteed 
                // that the managing actions can commit or roll back 
                // as a single unit of work.
                using (TransactionScope scope = new TransactionScope())
                {
                    // Enlist the manager.
                    manager.EnlistVolatile(EnlistmentOptions.None);

                    // Add here additional resource managers,
                    // such as database connections, that need
                    // enlisting in the current transaction.

                    // The Complete method commits the transaction. 
                    // If an exception has been thrown, Complete 
                    // is not called and the transaction is rolled back.
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Transaction aborted.");
                Console.WriteLine("Reason:");
                Console.WriteLine(e);
                transactionSuccessfullyCommitted = false;
            }
            finally
            {
                if (transactionSuccessfullyCommitted)
                {
                    Console.WriteLine("Transaction successfully committed.");
                }
            }
            bool fileExists = File.Exists(managedPath);
            Console.WriteLine("File exists? {0}.", fileExists);
            if (fileExists)
            {
                // We want to access the managed file to inspect its 
                // edited content, hence we need to dispose 
                // its manager.
                manager.Dispose();

                using (Stream stream = File.OpenRead(managedPath))
                {
                    XDocument savedDocument = XDocument.Load(stream);

                    Console.WriteLine("File content:");
                    Console.WriteLine(savedDocument);
                }
            }
        }
    }
}

// Executing method Main() produces the following output:
// 
// Transaction successfully committed.
// File exists? True.
// File content:
// <items>
//   <item>
//     <id>0001</id>
//     <description>A mysterious item</description>
//   </item>
//   <item>
//     <id>0002</id>
//     <description>A new item</description>
//   </item>
// </items>