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

前段时间看到了几篇关于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     }

 运行结果可想而知。

 

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

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

 

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

posted @ 2013-05-18 16:24  TimYang  阅读(1455)  评论(5编辑  收藏  举报