C#高级编程笔记(22至25章节)文件\注册表\权限\事务

22安全(using System.Security.Principal;)

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);//当前线程用户
var principal = WindowsPrincipal.Current as WindowsPrincipal; //window组成员
var identity = principal.Identity as WindowsIdentity; //用户,可用属性.name

24文件与注册表操作

  • FileSystemInfo 表示任何文件系统对象的基类。
  • FileInfo和File表示文件系统上的文件
  • DirectoryInfo和Directory表示文件系统上的文件夹。
  • Path这个类包含的静态成员可以用于处理路径名。
  • DriveInfo它的属性和方法提供了指定驱动器的信息。
  • System.MarshalByRefObject .NET类中用于远程操作的基对象类,允许在应用程序域之间编组数据。

属性

属性名称 属性作用
CreationTime 文件或文件夹创建时间
DirectoryName(仅用于文件类) 包含文件夹的完整路径名
Parent(仅用于文件夹类) 指定子目录的父目录
Exists 文件或文件夹是否存在
Extension 文件的扩展名,对于文件夹它返回空白
FullName 文件或文件夹的完整路径名
LastAccessTime 最后一次的访问文件或文件夹的时间
LastWriteTime 最后一次修改文件或文件夹的时间
Name 文件或文件夹的名称
Roct(仅用于文件夹类) 路径的根部分
Length(仅用于文件类) 返回文件的大小(以字节为单位)

操作方法

操作名称 操作作用
Create() 创建给定名称的文件夹或空文件,对于FilenInfo,该方法会返回一个流对象,经便写入文件.
Delete() 删除文件或文件夹,对于文件夹,有一个可以递归的Delete选项
MoveTo() 移动和/或重命名文件或文件夹
CopyTo() (只适用于FieInfo类)复制文件,注意文件夹没有复制方法.如果复制完整的目录树,需要单独复制每一个文件,创建对应于旧文件夹的新文件夹
GetDirectories() (只适用于DirectoryInfo)返回DirectoryInfo对象数组,该数组表示文件夹中包含的所有文件夹
GetFiles() (只适用于DirectoryInfo)返回FilesInfo对象数组,该数组表示文件夹中包含的所有文件.
EnumerateFiles() 返回文件名的IEnumerable<string>,在返回整个列表之前,可以对列表中的项执行操作
GetFileSystemInfos() (只适用于DirectoryInfo)返回FilesInfo和DirectoryInfo对象,它把文件夹中包含的所有对象表示为一个FileSystemInfo引用数组

流数数的操作方法有Open()、OpenRead()、OpenText()、OpenWrite()、Create()、CreateText()等方法,它们都是返回流对象。

Path类

path.Combine()//合并

FileProperties示例

try
            {
                string folderPath = txtBoxInput.Text;
                DirectoryInfo theFolder = new DirectoryInfo(folderPath);//得到 一个文件夹实例
                if (theFolder.Exists)//检测存在
                {
                    DisplayFolderList(theFolder.FullName);//执行方法
                    return;//返回
                }
                FileInfo theFile = new FileInfo(folderPath); //得到一个文件实例
                if (theFile.Exists)//检测存在
                {
                    DisplayFolderList(theFile.Directory.FullName);//执行方法
                    int index = listBoxFiles.Items.IndexOf(theFile.Name);//文件属性
                    listBoxFiles.SetSelected(index, true);
                    return;//返回
                }
                throw new FileNotFoundException("没有文件或文件夹 " + "this name: " + txtBoxInput.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

读取文件

  • File.ReadAllText(路径,Encoding.ASCII)//使用ASCII打开目标文件
  • File.ReadAllBytes()//返回字节数组
  • File.ReadAllLines()//逐行语取字符串返回数组

写入文件

  • File.WriteAllText(路径,字符串);//把字符串写入路径文件

FileSteam文件流

FileStream test =new FileStream(path,fileMode,FileAccess,FileShare) //相关参数见下表(以下值可以使用'|'进行合并使用)

枚举
path路径名 字符串路径
FileMode文件打开模式 Append追加,Create覆盖新建,CreateNew新建(存在则报错),Open打开(没有则报错),OpenOrCreate新建与打开(没有新建并打开)Truncate清除内容打开(慎用)
FileAccess文件访问权限 Read读取,ReadWrite读取写入,Write写入
FileShare文件共享方式 None独占,Read允许别的程序读取,Write允许别的程序写入,ReadWrite允许别的程序读取与写入
  • FileSteam.ReadByte();//读取一个字节,返回0-255的整数,如果到达流的末尾则返回-1
  • FileSteam.Read(ByteArray,0,nBytes);//把流写入一个ByteArray的字节数组中,参数0为偏移量,nBytes为字节数(参考网络传输文件),返回值为0时表示到达了流的末尾.
  • FileSteam.WritByte();//把一个字节写入流中,没有返回值
  • FileSteam.Writ(ByteArray,0,nBytes);//把一个字节数组写入流中,参数0为数组元素索引,后面为字节数,没有返回值

FileStream对象表示在磁盘或网络路径上指向文件的流。这个类提供了在文件中读写字节的方法,但经常使用StreamReader或 StreamWriter执行这些功能。这是因为FileStream类操作的是字节和字节数组,而Stream类操作的是字符数据。这是这两种类的一个重要区别,如果你是准备读取byte数据的话,用StreamReader读取然后用 System.Text.Encoding.Default.GetBytes转化的话,如下,则可能出现数据丢失的情况,如byte数据的个数不对等。因此操作byte数据时要用FileStream.

 

StreamReader类用于读取文本文件

  • StreamReader sr =  new StreamReader(FileStream实例);//FileStream(@"d:\123.txt",filemode.open,fileAccess.read)
  • StreamReader sr =  FileInfo实例.OpenText();
StreamReader方法 作用
ReadLine() 读取一行
ReadToEnd() 读取剩于的内容
Read() 读取一个字符

StreamWriter类用于写入文本文件

  • StreamWriter sw = new StreamWriter(@"D:\123.txt",true,Encoding.ASCII);以ASCII写入
  • StreamWriter sw = new StreamWriter(FileStream实例);
  • StreamWriter sw = FileInfo实例.CreateText();

相关文件操作方法

24映射内存的文件

主要用于减少I/O的操作,让CPU直接操作储存,操作请查阅网上资料

24.6读取驱动器信息

DriveInfo [] di = DriveInfo.GetDrives(); //获取计算机驱动器数组,可以使用Froeach
DriveInfo di1 = new DriveInfo(@"C:\");//获取C:\驱动器的实例

属性TotalSize总字节大小,TotalFreeSpace可用空间字节(为帐户磁盘配额),AvailableFreeSpace可用空间字节

24.7.1从文件中读取ACL(安全权限列表System.Security.AccessControl)

string myFilePath = @"D:\123.txt";
try
{
    using (FileStream myFile = new FileStream(myFilePath, FileMode.Open, FileAccess.Read))
    {
        FileSecurity fileSec = myFile.GetAccessControl();
        foreach (FileSystemAccessRule fileRule in fileSec.GetAccessRules(true, true, typeof(NTAccount)))
        {
            Console.WriteLine("{0} {1} {2} 通道出口 {3}", myFilePath, fileRule.AccessControlType == AccessControlType.Allow ? "提供" : "拒绝", fileRule.FileSystemRights, fileRule.IdentityReference);
        }
    }
}
catch
{
    Console.WriteLine("不正确的文件路径 !");
}
/*
输出
D:\123.txt 拒绝 FullControl 通道出口 YJCN\qibobo
D:\123.txt 提供 Modify, Synchronize 通道出口 NT AUTHORITY\Authenticated Users
D:\123.txt 提供 FullControl 通道出口 NT AUTHORITY\SYSTEM
D:\123.txt 提供 FullControl 通道出口 BUILTIN\Administrators
D:\123.txt 提供 FullControl 通道出口 BUILTIN\Users
 */

24.7.1从目录中读取ACL

如上面示例相同,FileStream改为

DirectoryInfo myDir = new DirectoryInfo(mentionedDir);
if (myDir.Exists) {DirectorySecurity myDirSec = myDir.GetAccessControl();程序2};//这里可以用myDirSec.GetAccessControl()

24.7.2添加ACL信息(加权限)

try
{
    using (FileStream myFile = new FileStream(@"d:\123.txt", FileMode.Open, FileAccess.ReadWrite))
    {
        FileSecurity filesec = myFile.GetAccessControl();//取得文件的权限列表
        FileSystemAccessRule newRule = new FileSystemAccessRule(new System.Security.Principal.NTAccount(@"YJCN\liganwei"), FileSystemRights.FullControl, AccessControlType.Allow);//表示一条新的权限条目,其中YJCN\liganwei可以是域/帐户 或计算机名/帐户
        filesec.AddAccessRule(newRule);//把上面的条目添加到列表中
        File.SetAccessControl(@"d:\123.txt", filesec);//把权限列表应用到文件中
    }
}
catch(ArgumentException ex)
{
    Console.WriteLine(ex);
}

24.8注册表

HKCR文件打开方式、  HKCU用户配置、 HKLM软件信息     注:软件一般存储在HKLM\Software\<CompanyName>键中

数据类型:REG_SZ(字符串),     REG_DWORD(int类型),    REG_BINARY(字节数组)

RegistryKey hklm = Registry.LocalMachine;
RegistryKey hkSoftware = hklm.OpenSubKey("Software",true);    //true表示写入权,无法写入注册表时,应该是注册表权限问题!把当前帐号加入权限      
RegistryKey hkMine = hkSoftware.CreateSubKey("MyOwnSoftware");//在software目录下建立MyOwnSoftware目录
hkMine.SetValue("MyStringValue", "Hello World");              //在MyOwnSoftware目录建立REG_DWORD子项
hkMine.SetValue("MyIntValiue", 20);                           //在MyOwnSoftware目录建立REG_DWORD子项
//hkMine.DeleteValue();删除键值 或DeleteSubKey()

24.9 写入独立存储器(System.IO.IsolatedStorage)

创建(主要学习XML的创建)

IsolatedStorageFile storFile = IsolatedStorageFile.GetUserStoreForDomain();  //创建独立存储文件实例
IsolatedStorageFileStream storStream = new IsolatedStorageFileStream("SelfPlacingWindow.Xml", FileMode.Create, FileAccess.Write);//创建独立存储文件流
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(storStream, Encoding.UTF8); //创建XmlTextWriter对象,以构建XMl文档,
writer.Formatting = System.Xml.Formatting.Indented; //设置格式子元素缩进
writer.WriteStartDocument(); //写入版本号为1.0的XML声明
writer.WriteStartElement("Settings"); //开始标记
writer.WriteValue(12); //
writer.WriteEndElement(); //结束标记
writer.Flush();
writer.Close();
storStream.Close();
storFile.Close();

读取(主要学习XML的读取)

IsolatedStorageFile storFile1 = IsolatedStorageFile.GetUserStoreForDomain(); //创建独立存储文件实例
String[] userFiles = storFile1.GetFileNames("SelfPlacingWindow.Xml");  //获取匹配文件名的文件,如果没带参数,返回所有    
foreach (string userFile in userFiles)  
{
    if(userFile == "SelfPlacingWindow.Xml")   //找到相应文件
    {
        StreamReader storStream1 = new StreamReader(new IsolatedStorageFileStream("SelfPlacingWindow.Xml", FileMode.Open, storFile1)); //流读取文件
        System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(storStream1);    ////创建XmlTextReader对象,读取文档        
        while (reader.Read())    //读取下个节点
        {
            switch (reader.Name)  //节点限定名
            {
                case "Settings":
                    Console.WriteLine(reader.ReadString());
                    break;
                default:
                    break;
            }
        }                   
    }
}
storFile1.Close();
userFiles.Clone();

25 事务

ACID属性

  • A原子性 
  • C 一致性
  • I 隔离性
  • D 持久性

25.3 数据库和实体类

SqlConnection connection = new SqlConnection( Properties.Settings.Default.CourseManagementConnectionString);
      SqlCommand courseCommand = connection.CreateCommand(); 
      courseCommand.CommandText ="INSERT INTO Courses (Number, Title) VALUES (@Number, @Title)";
      await connection.OpenAsync();
      SqlTransaction tx = connection.BeginTransaction(); //事务开始
      try
      {
        courseCommand.Transaction = tx; //加入事务
        courseCommand.Parameters.AddWithValue("@Number", course.Number);
        courseCommand.Parameters.AddWithValue("@Title", course.Title);
        await courseCommand.ExecuteNonQueryAsync();
        tx.Commit(); //提交事务
      }
      catch (Exception ex)
      {
        Trace.WriteLine("Error: " + ex.Message);
        tx.Rollback(); //回滚事务
        throw;
      }
      finally
      {
        connection.Close();
      }

25.4传统事务

SQLConnection类  BeginTransaction()开始事务,  Commit()提交事务 Rollback() 回滚事务

25.4.2 System.EnterpriseServices 优点是自动登陆事务,要派生基类(少用)

25.5 System.Transaction

25.5.1可提交的事务

相关代码查阅书本

SqlConnection connection = new SqlConnection(Properties.Settings.Default.CourseManagementConnectionString);
      await connection.OpenAsync();
      try
      {
        if (tx != null) connection.EnlistTransaction(tx); //检测事务是否有事务实例,把sql连接装入事务
....
wait command.ExecuteNonQueryAsync();
}
var tx = new CommittableTransaction();
 try
      {       
        await db.AddStudentAsync(s1, tx);
        tx.Commit();
      }
catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
        Console.WriteLine();
        tx.Rollback();
      }

25.5.2 事务处理的升级

代码与上示例相同,

await db.AddStudentAsync(s1, tx);
await db.AddStudentAsync(s2, tx);//事务升级需要启动分布式事务协调器(DTC) 在windows服务里可以找到MS DTC

可以在设置超时时间!请查看书本

25.5.3依赖事务

static void DependentTransaction()
{
  var tx = new CommittableTransaction(); //根事务
  Utilities.DisplayTransactionInformation("TX创建根", tx.TransactionInformation);
  try
  {
    Task.Factory.StartNew(TxTask, tx.DependentClone(DependentCloneOption.BlockCommitUntilComplete)); //创建依赖事务Transaction.DependentClone 方法返回一个依赖事务,阻塞父事务
            if (Utilities.AbortTx()){throw new ApplicationException("transaction abort");}
    tx.Commit(); //尝试提交事务
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
    tx.Rollback(); //回滚事务
  }
  Utilities.DisplayTransactionInformation("TX 完成了",tx.TransactionInformation);
}
static void TxTask(object obj)
{
  var tx = obj as DependentTransaction;
  Utilities.DisplayTransactionInformation("相关事务",tx.TransactionInformation);
  Thread.Sleep(3000);
  tx.Complete();//尝试完成依赖事务
  Utilities.DisplayTransactionInformation("相关TX完成",tx.TransactionInformation);
}

25.5.4环境事务

事务完成时的事件设置调用OnTransactionCompleted方法,因为SQLConnection支持环境事务,并且会自动通过连接登记它

static async Task TransactionScopeAsync()
{
  using (var scope = new TransactionScope())
  {
    Transaction.Current.TransactionCompleted += OnTransactionCompleted; //为环境事务的TransactionCompleted完成事件加入OnTransactionCompleted方法
    Utilities.DisplayTransactionInformation("Ambient TX created", Transaction.Current.TransactionInformation);
    var s1 = new Student { FirstName = "Angela",LastName = "Nagel",Company = "Kantine M101"};
    var db = new StudentData();
    await db.AddStudentAsync(s1);
    if (!Utilities.AbortTx())
      scope.Complete();//指示范围中的所有操作都已成功完成。
      else
      Console.WriteLine("transaction will be aborted");                
  }
        // scope.Dispose();这里代表结束事务,如果没调用Complete()方法,就应该调Dispose()方法结束事务
 }
    static void OnTransactionCompleted(object sender, TransactionEventArgs e)
{
  Utilities.DisplayTransactionInformation("TX completed",e.Transaction.TransactionInformation);
}

1嵌套的作用域和环境事务

TransactionScopeOption枚举的值:

  • Required(需要的)嵌套的事务要提交后才生效          
  • Required(新的事务)二个独立的事务               
  • Suppress(取消事务)

相关连接

2多线程与环境事务

try
{
  using (var scope = new TransactionScope())
  {
    Transaction.Current.TransactionCompleted += TransactionCompleted; //完成时输出
    Utilities.DisplayTransactionInformation("Main thread TX",Transaction.Current.TransactionInformation);
    Task.Factory.StartNew(TaskMethod, Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete));//创建依赖事务,如果这里没有依赖事务选项,则因是不同的线程,所以是二个不同的事务
    scope.Complete();
  }
}
catch (TransactionAbortedException ex)
{
  Console.WriteLine("Main—Transaction was aborted, {0}",ex.Message);
}

25.6隔离级别

隔离级别 脏读 不可重复读 幻读
ReadUncommitted (可读取修改可变数据) Y Y Y
ReadCommitted (可读取不可修改可变数据) N Y Y
RepeatableRead (可读取不可修改可变数据,可添加) N N Y
Serializable (可读取不可修改可变数据,不可添加) N N N
var options = new TransactionOptions
{
    IsolationLevel = IsolationLevel.ReadUncommitted,Timeout = TimeSpan.FromSeconds(90) //设置事务可读可修改可变数据,超时设置为90毫秒
};
using (var test = new TransactionScope(TransactionScopeOption.Required, options))
{
}

25.7自定义资源管理器

此节涉及"浅拷贝"与"深拷贝"的相关知识 请先查看 相关的知识点

因理解问题,以下是Transactions的所有代码注释

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Transactions;

namespace Wrox.ProCSharp.Transactions
{
    public  class Transactional<T>
    {
        private T liveValue; //实时值
        private ResourceManager<T> enlistment; //临时值
        private Transaction enlistedTransaction; //事务

        public Transactional(T value)
        {
            if (Transaction.Current == null)
            {
                this.liveValue = value;
            }
            else
            {
                this.liveValue = default(T);
                GetEnlistment().Value = value;
            }
        }

        public Transactional(): this(default(T)) { }

        /// <summary>
        /// 检测是否在环境事务中,如果有
        /// </summary>
        /// <returns></returns>
        private ResourceManager<T> GetEnlistment()
        {
            Transaction tx = Transaction.Current; //获取环境事务
            Trace.Assert(tx != null, "必须用环境事务调用");//检查条件;如果条件为 false,则输出消息并显示一个消息框,后者用于显示调用堆栈。
            if (enlistedTransaction == null)//如果没有登记事务
            {
                enlistment = new ResourceManager<T>(this, tx); //实例化内部类
                tx.EnlistVolatile(enlistment, EnlistmentOptions.None); //登记事务
                enlistedTransaction = tx; 
                return enlistment;
            }
            else if (enlistedTransaction == Transaction.Current) //查看是否是在同一线程中4
            {
                return enlistment; //返回资源管理器
            }
            else
            {
                throw new TransactionException("此类仅支持与一个事务一起使用的列表");
            }
        }


        public T Value
        {
            get { return GetValue(); }
            set { SetValue(value); }
        }
        protected virtual T GetValue()
        {
            if (Transaction.Current == null)
            {
                return liveValue;
            }
            else
            {
                return GetEnlistment().Value;
            }
        }

        protected virtual void SetValue(T value)
        {
            if (Transaction.Current == null)
            {
                liveValue = value;
            }
            else
            {
                GetEnlistment().Value = value;
            }
        }
        /// <summary>
        /// 提交事务的方法
        /// </summary>
        /// <param name="value"></param>
        /// <param name="tx"></param>
        internal void Commit(T value, Transaction tx)
        {
            liveValue = value;
            enlistedTransaction = null;
        }
        /// <summary>
        /// 回滚事务的方法
        /// </summary>
        /// <param name="tx"></param>
        internal void Rollback(Transaction tx)
        {
            enlistedTransaction = null;
        }
        internal class ResourceManager<T1> : IEnlistmentNotification //内部类,只有当前项目可以访问
        {
            private Transactional<T1> parent; //临时值()
            public T1 Value { get; set; } //实时值
            private Transaction currentTransaction;//事务

            internal ResourceManager(Transactional<T1> parent, Transaction tx)
            {
                this.parent = parent;
                Value = DeepCopy(parent.liveValue);//序列化"parent.liveValue"
                currentTransaction = tx;//事务
            }            

            static ResourceManager()
            {
                Type t = typeof(T1);//获取类型类型
                //Assert方法检查条件;如果条件为 false,则输出消息并显示一个消息框,后者用于显示调用堆栈。
                Trace.Assert(t.IsSerializable, "Type " + t.Name + " 不可串行化");//Type.IsSerializable 属性如果可序列化则为 true;否则为 false。 
            }
            /// <summary>
            /// 序列化对象到流中
            /// </summary>
            /// <param name="value">对象</param>
            /// <returns></returns>
            private static T1 DeepCopy(T1 value)
            {
                using (var stream = new MemoryStream())
                {
                    var formatter = new BinaryFormatter();//以二进制格式将对象或整个连接对象图形序列化和反序列化。
                    formatter.Serialize(stream, value);//序列化value到stream流中
                    stream.Flush();//当重写Flush方法时,将清除该流的所有缓冲区,并使得所有缓冲数据被写入到基础设备
                    stream.Seek(0, SeekOrigin.Begin);//将当前流中的位置设置为指定值。
                    return (T1)formatter.Deserialize(stream);//返回 将流反序列化为对象图形。
                }
            }
            public void Prepare(PreparingEnlistment preparingEnlistment)
            {
                preparingEnlistment.Prepared();
            }

            public void Commit(Enlistment enlistment)
            {
                parent.Commit(Value, currentTransaction);
                enlistment.Done();
            }

            public void Rollback(Enlistment enlistment)
            {
                parent.Rollback(currentTransaction);
                enlistment.Done();
            }

            public void InDoubt(Enlistment enlistment)
            {
                enlistment.Done();
            }
        }
    }


}
Transactional类
ng System;
using System.Diagnostics.Contracts;
using System.Transactions;

namespace Wrox.ProCSharp.Transactions
{
  public static class Utilities
  {
    public static bool AbortTx()
    {
      Console.Write("中止事务 (y/n)?");
      return Console.ReadLine().ToLower().Equals("y");
    }

    public static void DisplayTransactionInformation(string title, TransactionInformation ti)
    {
      if (ti == null) { throw new Exception("事务不能为空"); }
      Console.WriteLine(title);
      Console.WriteLine("创建 Time: {0:T}", ti.CreationTime);
      Console.WriteLine("状态: {0}", ti.Status);
      Console.WriteLine("本地 ID: {0}", ti.LocalIdentifier);
      Console.WriteLine("分布式 ID: {0}", ti.DistributedIdentifier);
      Console.WriteLine();
    }
  }

}
Utilities中断事务方法

以上是理解主要在于添加了接口与序列化的问题!请细心解读

25.8文件事务

因此节涉及COM的相关知识,这里不做解读!!直接拿着用吧!!在代码中加下面类

using System;
using System.Runtime.InteropServices;

namespace Wrox.ProCSharp.Transactions
{
    [ComImport]
    [Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IKernelTransaction
    {
        void GetHandle(out SafeTransactionHandle ktmHandle);
    }
}
IKernelTransaction.cs
using System;
using System.Security;
using System.Security.Permissions;
using System.Security.AccessControl;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;

namespace Wrox.ProCSharp.Transactions
{
    [SecurityCritical]
    internal static class NativeMethods
    {
        [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall,
                   CharSet = CharSet.Unicode)]
        internal static extern SafeFileHandle CreateFileTransacted(
            String lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr lpSecurityAttributes,
            uint dwCreationDisposition,
            int dwFlagsAndAttributes,
            IntPtr hTemplateFile,
            SafeTransactionHandle txHandle,
            IntPtr miniVersion,
            IntPtr extendedParameter);

        [DllImport("Kernel32.dll", SetLastError = true)]
        [ResourceExposure(ResourceScope.Machine)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool CloseHandle(IntPtr handle);

    }
}
NativeMethods.cs
using System;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;


namespace Wrox.ProCSharp.Transactions
{
  [SecurityCritical]
  internal sealed class SafeTransactionHandle : SafeHandleZeroOrMinusOneIsInvalid
  {
    private SafeTransactionHandle(): base(true) { } //安全事务句柄
    public SafeTransactionHandle(IntPtr preexistingHandle, bool ownsHandle): base(ownsHandle)
    {
      SetHandle(preexistingHandle);
    }
    [ResourceExposure(ResourceScope.Machine)]
    [ResourceConsumption(ResourceScope.Machine)]
    protected override bool ReleaseHandle()
    {
      return NativeMethods.CloseHandle(handle);
    }
  }

}
SafeTransactionHandle.cs
using System;
using System.IO;
using System.Security.Permissions;
using System.Transactions;
using Microsoft.Win32.SafeHandles;

namespace Wrox.ProCSharp.Transactions
{
  public static class TransactedFile
  {
    internal const short FILE_ATTRIBUTE_NORMAL = 0x80;
    internal const short INVALID_HANDLE_VALUE = -1;
    internal const uint GENERIC_READ = 0x80000000;
    internal const uint GENERIC_WRITE = 0x40000000;
    internal const uint CREATE_NEW = 1;
    internal const uint CREATE_ALWAYS = 2;
    internal const uint OPEN_EXISTING = 3;

    [FileIOPermission(SecurityAction.Demand, Unrestricted = true)]
    public static FileStream GetTransactedFileStream(string fileName)
    {
      IKernelTransaction ktx = (IKernelTransaction)
            TransactionInterop.GetDtcTransaction(Transaction.Current);

      SafeTransactionHandle txHandle;
      ktx.GetHandle(out txHandle);

      SafeFileHandle fileHandle = NativeMethods.CreateFileTransacted(
            fileName, GENERIC_WRITE, 0,
            IntPtr.Zero, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
            IntPtr.Zero,
            txHandle, IntPtr.Zero, IntPtr.Zero);

      return new FileStream(fileHandle, FileAccess.Write);
    }
  }
}
TransactedFile.cs

调用方法如下:

using System;
using System.IO;
using System.Transactions;
namespace Wrox.ProCSharp.Transactions
{
  class Program
  {
    static void Main()
    {
      WriteFileSample();
    }
    static async void WriteFileSample()
    {
      using (var scope = new TransactionScope())
      {
        FileStream stream = TransactedFile.GetTransactedFileStream("sample.txt");
        var writer = new StreamWriter(stream);
        await writer.WriteLineAsync("Write a transactional file");
        writer.Close();
        if (!Utilities.AbortTx())
          scope.Complete();
      }
    }
  }
}
posted @ 2017-12-27 17:53  天祈笨笨  阅读(478)  评论(0编辑  收藏  举报