• 学习之路之三十:利用消息机制自定义数据库回滚特性


    前段时间看到了几篇关于Attribute相关的文章,里面讲的很详细,参考:Attribute在.NET编程中的应用(五)

    不过让我收获最多的关于“.NET Framework拦截机制的内容”,而且这也让我解决了一年前提出的问题!

    地址:急丶急丶急 → 关于特性和IOC或者AOP的结合,其实跟IOC和AOP一点关于都没有,只是当时知识积累还不够,对解决问题的能力还不足!

    下面我就结合一些理论知识以及对上面提出的案例进行改装,使它能够运用一般的方法之中(自定义一个数据库回滚特性)!

    1.定义一个RollBack的特性

     1     [AttributeUsage(AttributeTargets.Method)]
     2     public class RollBackAttribute : Attribute
     3     {
     4         private bool _isCommit = true;
     5 
     6         public RollBackAttribute()
     7         { }
     8 
     9         public bool IsCommit //定义一个属性提示是否要提交数据
    10         {
    11             get { return _isCommit; }
    12             set { _isCommit = value; }
    13         }
    14     }

    2.定义一个消息接收器

      1     public class RollBackMessageSink : IMessageSink
      2     {
      3         //定义下一个消息接收器实例
      4         private IMessageSink _nextSink;
      5 
      6         public RollBackMessageSink(IMessageSink messageSink) //通过构造函数来传递下一个消息接收器
      7         {
      8             _nextSink = messageSink;
      9         }
     10 
     11         //异步执行消息,一般情况下不需要写任何逻辑
     12         public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
     13         {
     14             throw new NotImplementedException();
     15         }
     16 
     17         public IMessageSink NextSink
     18         {
     19             get
     20             {
     21                 return _nextSink;
     22             }
     23         }
     24 
     25         //同步执行消息
     26         public IMessage SyncProcessMessage(IMessage msg)
     27         {
     28             //这边就是最重要的代码了
    //有一点要说明的:如果调用[_nextSink.SyncProcessMessage(msg)]就说明方法已经执行好了
    //这边有一个前处理和后处理的概念
    //前处理:也就是调用方法前的处理事件
    //后处理:也就是方法调用结束后的处理事件
    //前处理和后处理的标记:就是是否调用了[_nextSink.SyncProcessMessage(msg)],调用之前就是前处理,反之是后处理 66 RollBackAttribute rollBack = GetRollBackAttribute(msg); 67 if (rollBack == null) return _nextSink.SyncProcessMessage(msg); 68 if (rollBack.IsCommit) 69 { 70 using (TransactionScope scope = new TransactionScope()) 71 { 72 return _nextSink.SyncProcessMessage(msg); 73 } 74 } 75 return _nextSink.SyncProcessMessage(msg); 76 } 77 78 private RollBackAttribute GetRollBackAttribute(IMessage msg) 79 { 80 //特别要注意["__TypeName"],其实这边是两个下划线,这个一定要记,可以通过调试来查看
    81 string typeName = (string)msg.Properties["__TypeName"];
    82 string methodName = (string)msg.Properties["__MethodName"]; 83 84 Console.WriteLine(typeName); 85 Console.WriteLine(methodName); 86 87 //根据类型和方法名获取自定义特性 88 object[] customAttributes = Type.GetType(typeName).GetMethod(methodName).GetCustomAttributes(true); 89 if (customAttributes != null && customAttributes.Length > 0) 90 { 91 RollBackAttribute rollback = customAttributes[0] as RollBackAttribute; 92 if (rollback != null) 93 { 94 //Console.WriteLine("是个对象啦"); 95 return rollback; 96 } 97 } 98 return null; 99 } 100 }

     3.下面来定义上下文属性,只要把消息接收器放到上下文中才行

     1     //必须要实现下面两个接口的
     2     //接下来我们定义上下文环境的属性,上下文环境属性必须根据你要创建的接收器类型来实现相应的接口,
     3     //比如:如果创建的是服务器上下文环境接收器,那么必须实现IContributeServerContextSink接口。 
     4     public class RollBackProperty : IContributeObjectSink, IContextProperty
     5     {
     6         //从接口名可以很清楚的看出来,通过这个上下文把消息接收器加到消息链中去
     7         //添加对象链
     8         #region IContributeObjectSink Members
     9 
    10         //这个方法就是最重要的了
    11         public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
    12         {
    13             //获取当前的消息接收器的实例
    14             return new RollBackMessageSink(nextSink);
    15         }
    16 
    17         #endregion
    18 
    19         #region IContextProperty Members
    20 
    21         //一般情况下不要实现,高级代码,o(∩_∩)o 哈哈
    22         //终结对象
    23         public void Freeze(Context newContext)
    24         {
    25 
    26         }
    27 
    28         //这是是问你是否想要创建新的上下文实例
    29         public bool IsNewContextOK(Context newCtx)
    30         {
    31             //默认情况下都是返回true
    32             return true;
    33         }
    34 
    35         public string Name
    36         {
    37             get
    38             {
    39                 //可以任意指定字符串
    40                 return "XXXXXXXXXXXXX";
    41             }
    42         }
    43 
    44         #endregion
    45     }

     4.倒数第二步了,定义特性,把第三个定义的属性加到运行时的上下文中去

     1     [AttributeUsage(AttributeTargets.Class)]
     2     public class RollBackContextAttribute: ContextAttribute
     3     {
     4         public RollBackContextAttribute()
     5             : base("VVVVVVVV")
     6         { }
     7 
     8         public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
     9         {
    10             //把自定义好的上下文实例添加到上下文集合中去
    11             ctorMsg.ContextProperties.Add(new RollBackProperty());
    12         }
    13     }

    5.最后一步,定义一个回滚帮助类

    1     [RollBackContext]
    2     //必须继承这个类,只有继承这个类才能使对象在多个上下文边界中进行传递
    3     public class RollBackHandler : ContextBoundObject
    4     {
    5     }

    6.测试

     1     public class TestRollBack : RollBackHandler //必须继承这个回滚助手类
     2     {
     3         [通过消息机制实现回滚特性.RollBack] //为方法添加RollBack特性
     4         public void MyTest()
     5         {
     6             SqlConnectionStringBuilder connectionString = new SqlConnectionStringBuilder();
     7             connectionString.DataSource = @"LBDZ-20120514VC\SQLEXPRESS";
     8             connectionString.InitialCatalog = "My";
     9             connectionString.IntegratedSecurity = true;
    10 
    11             using (SqlConnection conn = new SqlConnection(connectionString.ToString()))
    12             {
    13                 conn.Open();
    14                 string strSQL = "INSERT dbo.MyNames (ListName) VALUES ( 'XXXXX')";
    15                 SqlCommand cmd = conn.CreateCommand();
    16                 cmd.CommandText = strSQL;
    17                 cmd.ExecuteNonQuery();
    18             }
    19         }
    20     }

     运行结果可想而知。

    好了,其实还没有对这些知识点内部机制有个很熟的理解,不过通过自己的动手实验,也让自己明白了这些东西是怎么个回事!

    通过这件事也让俺明白了很多时候并不是你不笨,只是你的经验还不够,你的知识积累还很少,其实很多知识要领到了一定时候自然会明白的!

    以同步至:个人文章目录索引

  • 相关阅读:
    个人图床【Gitee+PicGo(+Typora)】
    java 对象序列化
    @RequestParam和@PathVariable
    restful架构
    数组跟切片的区别
    为什么java支持 一个类实现多个接口;但是只能继承一个类
    == 与equals区别
    static代码块是先加载的,不能用成员变量。可以new。
    @Configuration和 @Bean
    Thymeleaf 常用th标签基础整理
  • 原文地址:https://www.cnblogs.com/yangcaogui/p/3077560.html
Copyright © 2020-2023  润新知