




已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
前言 使用Attribute来实现方法级别事务一直是我的梦想,浅谈Attribute C# | Attribute | DefaultValueAttribute有体现我的无奈,Attribute确实是真真切切的非侵入式的东西(其实我是想侵入的: ) ),前有DUDU的Attribute在.net编程中的应用系列文章,但是总是离想象和需求有那么点出入,通过三天的努力,Google的陪伴,下面和大家一起分享我这三天的成果 用Attribute实现AOP事务 吧! 致谢文章 1. Aspect-Oriented Programming Enables Better Code Encapsulation and Reuse 关键性的CallContext是在这里发现的。 2. C# Attribute在.net编程中的应用 (转)这篇文章原文地址找不到了,DUDU的Attribute在.net编程中的应用系列文章就是这篇文章的分解,他写到了五,后面的大家可以从这篇文章里面提前看到了。 阅前注意 1. 整篇文章的核心和突破点在于上下文Context的使用,务必注意CallContext在整个程序中起到的作用 2. 本文中看到的SqlHelper使用的是微软SqlHelper.cs。 3. 本文重点在于如何实现,并且已经测试通过,只贴关键性代码,所以请认真阅读,部分代码直接拷贝下来运行是会出错的! 正文 首先我们来看一段未加事务的代码: SqlDAL.cs public abstract class SqlDAL #region ConnectionString private SqlConnectionStringBuilder _ConnectionString = null; / / 字符串连接 / public virtual SqlConnectionStringBuilder ConnectionString get if (_ConnectionString = null | string.IsNullOrEmpty(_ConnectionString.ConnectionString) _ConnectionString = new SqlConnectionStringBuilder(Configurations.SQLSERVER_CONNECTION_STRING); return _ConnectionString; set _ConnectionString = value; #endregion #region ExecuteNonQuery public int ExecuteNonQuery(string cmdText) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, CommandType.Text, cmdText); public int ExecuteNonQuery(string cmdText, CommandType type) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText); public int ExecuteNonQuery(string cmdText, CommandType type, params SqlParameter cmdParameters) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText, cmdParameters); #endregion 代码说明: 1. 本类对SqlHelper.cs 进一步封装。 2. Configurations.SQLSERVER_CONNECTION_STRING 替换成自己的连接字符串就行了。 UserInfoAction.cs public class UserInfoAction : SqlDAL / / 添加用户 / public void Add(UserInfo user) StringBuilder sb = new StringBuilder(); sb.Append(UPDATE UserInfo SET Password=); sb.Append(user.Password); sb.Append( WHERE UID=); sb.Append(user.UID); ExecuteNonQuery(sql); 如果我们要加入事务,通常的办法就是在方法内try、catch然后Commit、Rollback,缺点就不说了,下面我会边贴代码边讲解,力图大家也能掌握这种方法: ) 先贴前面两个被我修改的类 SqlDAL.cspublic abstract class SqlDAL : ContextBoundObject private SqlTransaction _SqlTrans; / / 仅支持有事务时操作 / public SqlTransaction SqlTrans get if (_SqlTrans = null) /从上下文中试图取得事务 object obj = CallContext.GetData(TransactionAop.ContextName); if (obj != null & obj is SqlTransaction) _SqlTrans = obj as SqlTransaction; return _SqlTrans; set _SqlTrans = value; #region ConnectionString private SqlConnectionStringBuilder _ConnectionString = null; / / 字符串连接 / public virtual SqlConnectionStringBuilder ConnectionString get if (_ConnectionString = null | string.IsNullOrEmpty(_ConnectionString.ConnectionString) _ConnectionString = new SqlConnectionStringBuilder(Configurations.SQLSERVER_CONNECTION_STRING); return _ConnectionString; set _ConnectionString = value; #endregion #region ExecuteNonQuery public int ExecuteNonQuery(string cmdText) if (SqlTrans = null) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, CommandType.Text, cmdText); else return SqlHelper.ExecuteNonQuery(SqlTrans, CommandType.Text, cmdText); public int ExecuteNonQuery(string cmdText, CommandType type) if (SqlTrans = null) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText); else return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText); public int ExecuteNonQuery(string cmdText, CommandType type, params SqlParameter cmdParameters) if (SqlTrans = null) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText, cmdParameters); else return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText, cmdParameters); #endregion 代码说明: 1. 加了一个属性(Property)SqlTrans,并且每个ExecuteNonQuery执行前都加了判断是否以事务方式执行。这样做是为后面从上下文中取事务做准备。 2. 类继承了ContextBoundObject,注意,是必须的,MSDN是这样描述的:定义所有上下文绑定类的基类。 3. TransactionAop将在后面给出。 UserInfoAction.cs Transaction public class UserInfoAction : SqlDAL TransactionMethod public void Add(UserInfo user) StringBuilder sb = new StringBuilder(); sb.Append(UPDATE UserInfo SET Password=); sb.Append(user.Password); sb.Append( WHERE UID=); sb.Append(user.UID); ExecuteNonQuery(sql); 代码说明: 1. 很简洁、非侵入式、很少改动、非常方便(想要事务就加2个标记,不想要就去掉)。 2. 两个Attribute后面将给出。 / / 标注类某方法内所有数据库操作加入事务控制 / AttributeUsage(AttributeTargets.Class, AllowMultiple = false) public sealed class TransactionAttribute : ContextAttribute, IContributeObjectSink / / 标注类某方法内所有数据库操作加入事务控制,请使用TransactionMethodAttribute同时标注 / public TransactionAttribute() : base(Transaction) public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next) return new TransactionAop(next); / / 标示方法内所有数据库操作加入事务控制 / AttributeUsage(AttributeTargets.Method, AllowMultiple = false) public sealed class TransactionMethodAttribute : Attribute / / 标示方法内所有数据库操作加入事务控制 / public TransactionMethodAttribute() 代码说明: 1. 在上面两篇文章中都是把IContextProperty, IContributeObjectSink单独继承并实现的,其实我们发现ContextAttribute已经继承了IContextProperty,所有这里我仅仅只需要再继承一下IContributeObjectSink就行了。关于这两个接口的说明,上面文章中都有详细的说明。 2. TransactionAop将在后面给出。 3. 需要注意的是两个Attribute需要一起用,并且我发现Attribute如果标记在类上他会被显示的实例化,但是放在方法上就不会,打断点可以跟踪到这一过程,要不然我也不会费力气弄两个来标注了。 TransactionAop.cspublic sealed class TransactionAop : IMessageSink private IMessageSink nextSink; /保存下一个接收器 / / 构造函数 / / 接收器 public TransactionAop(IMessageSink nextSink) this.nextSink = nextSink; / / IMessageSink接口方法,用于异步处理,我们不实现异步处理,所以简单返回null, / 不管是同步还是异步,这个方法都需要定义 / / / / public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) return null; / / 下一个接收器 / public IMessageSink NextSink get return nextSink; / / / / / public IMessage SyncProcessMessage(IMessage msg) IMessage retMsg = null; IMethodCallMessage call = msg as IMethodCallMessage; if (call = null | (Attribute.GetCustomAttribute(call.MethodBase, typeof(TransactionMethodAttribute) = null) retMsg = nextSink.SyncProcessMessage(msg); else /此处换成自己的数据库连接 using (SqlConnection Connect = new SqlConnection(Configurations.SQLSERVER_CONNECTION_STRING) Connect.Open(); SqlTransaction SqlTrans = Connect.BeginTransaction(); /讲存储存储在上下文 CallContext.SetData(TransactionAop.ContextName, SqlTrans); /传递消息给下一个接收器 - 就是指执行你自己的方法 retMsg = nextSink.SyncProcessMessage(msg); if (SqlTrans != null) IMethodReturnMessage methodReturn = retMsg as IMethodReturnMessage; Exception except = methodReturn.Exception; if (except != null) SqlTrans.Rollback(); /可以做日志及其他处理 else SqlTrans.Commit(); SqlTrans.Dispose(); SqlTrans = null; return retMsg; / / 用于提取、存储SqlTransaction / public static string ContextName get return TransactionAop; 代码说明: 1. IMessageSink MSDN:定义消息接收器的接口。 2. 主要关注SyncProcessMessage方法内的代码,在这里创建事务,并存储在上下文中间,还记得上面SqlDAL的SqlTrans属性么,里面就是从上下文中取得的。 3. 请注意了,这里能捕捉到错误,但是没有办法处理错误,所以错误会继续往外抛,但是事务的完整性我们实现了。你可以在Global.asax可以做全局处理,也可以手动的try一下,但是我们不需要管理事务了,仅仅当普通的错误来处理了。 结束 大家可以看到,在被标注的方法里面所有的数据库
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 火安全知识培训课件
- 巡检员专业知识培训总结课件
- 年产3万套轻量化材料应用项目可行性研究报告
- 年产30万吨有机硅流化床项目可行性研究报告
- 奥尔夫乐器课件
- 年产62万套建筑光伏遮阳板项目可行性研究报告
- 激光仪器基础知识培训课件
- 年产1.8万吨碳化硅晶体生长炉项目可行性研究报告
- 二零二五年度防雷设备生产与质量控制合同范本
- 2025版陶瓷产品设计开发委托合同模板
- 2025《煤矿安全规程》新旧对照专题培训
- 猪细菌病的诊断综合实验方案
- JJG 1036-2022电子天平
- GB/T 27703-2011信息与文献图书馆和档案馆的文献保存要求
- GB/T 14188-2008气相防锈包装材料选用通则
- 初中全册英语常用3500词分类大全
- 工程质量通病防治措施专项施工方案
- 设备检修管理流程图
- 堤防工程重点难点
- 卸料平台(落地搭设)验收记录表
- 新媒体研究方法教学ppt课件(完整版)
评论
0/150
提交评论