分享关于过程的事务处理类
1 using System;
2 using System.EnterpriseServices;
3 using System.Runtime.InteropServices;
4 using System.Reflection;
5
6 [assembly: ApplicationActivation(ActivationOption.Library)]
7 [assembly: ApplicationID("77769CB1-A707-11D0-989D-00C04FD444E4")]
8 [assembly: ApplicationName("SAF.Transaction")]
9 namespace MyControl.SAFApplication
10 {
11 /// <summary>
12 /// Interface each transaction controller must implement.
13 /// </summary>
14 public interface ITransactionController
15 {
16 object ExecuteMethod(object o, string method, params object[] p);
17 void Rollback();
18 void Commit();
19 }
20
21 /// <summary>
22 /// TransactionControllerBase is the base class for serviced components in SAF.Transaction.
23 /// It provides a way to execute business method as part of the transaction context and abilities
24 /// to commit and rollback transactions.
25 /// </summary>
26 public abstract class TransactionControllerBase : System.EnterpriseServices.ServicedComponent,ITransactionController
27 {
28
29 public virtual object ExecuteMethod(object o, string method, params object[] p )
30 {
31 try
32 {
33 //use the reflection to invoke the business method within the current transaction scope.
34 return o.GetType().InvokeMember(method,BindingFlags.InvokeMethod,null,o,p);
35 }
36 catch (Exception ex)
37 {
38 //if exception occurs, mark the current transaction as such so that we can
39 //rollback the transaction later.
40 if (ContextUtil.IsInTransaction)
41 {
42 ContextUtil.DisableCommit();
43 }
44 //rethow the exception to notify the caller.
45 throw ex;
46 }
47 }
48
49 /// <summary>
50 /// Rollback method set abort the current transaction.
51 /// </summary>
52 public virtual void Rollback()
53 {
54 //if it is part of a transaction, abort it.
55 if (ContextUtil.IsInTransaction)
56 {
57 ContextUtil.SetAbort();
58 }
59 }
60
61 /// <summary>
62 /// Commit method commit the current transaction if all the transaction vode
63 /// are good.
64 /// </summary>
65 public virtual void Commit()
66 {
67 //check if it is in a transaction
68 if (ContextUtil.IsInTransaction)
69 {
70 //check if the transaction vote is good. if so, set complete on the transaction
71 //otherwise, abort the transaction.
72 if (ContextUtil.MyTransactionVote == TransactionVote.Commit)
73 {
74 ContextUtil.SetComplete();
75 }
76 else
77 {
78 ContextUtil.SetAbort();
79 }
80 }
81 }
82 }
83
84
85 /// <summary>
86 /// Provide the Manager class that
87 /// clients interact when creating different type of transaction compnent.
88 /// </summary>
89 public class TransactionManager
90 {
91 /// <summary>
92 /// Return a new serviced component that supports transaction
93 /// </summary>
94 /// <returns>SupportTransaction object</returns>
95 public static ITransactionController GetSupportTransactionController()
96 {
97 return new SupportTransaction();
98 }
99
100 /// <summary>
101 /// Return a new service component that require transaction
102 /// </summary>
103 /// <returns>RequireTransaction object</returns>
104 public static ITransactionController GetRequireTransactionController()
105 {
106 return new RequireTransaction();
107 }
108
109 /// <summary>
110 /// Return a new service component that require new transaction
111 /// </summary>
112 /// <returns>RequireNewTransaction object</returns>
113 public static ITransactionController GetRequireNewTransactionController()
114 {
115 return new RequireNewTransaction();
116 }
117
118 /// <summary>
119 /// Return a new service component with no transaction
120 /// </summary>
121 /// <returns>NoTransaction object</returns>
122 public static ITransactionController GetNoTransactionController()
123 {
124 return new NoTransaction();
125 }
126
127 /// <summary>
128 /// Helper method that will rollback array of ITransactionController objects
129 /// </summary>
130 /// <param name="txControllers">ITransactionController array</param>
131 public static void Rollback(params ITransactionController[] txControllers)
132 {
133 foreach (ITransactionController txController in txControllers)
134 {
135 if (txController != null)
136 {
137 txController.Rollback();
138 }
139
140 }
141 }
142
143 /// <summary>
144 /// Helper method that will commit array of ITransactionController objects
145 /// </summary>
146 /// <param name="txControllers">ITransactionController array</param>
147 public static void Commit(params ITransactionController[] txControllers)
148 {
149 foreach (ITransactionController txController in txControllers)
150 {
151 if (txController != null)
152 {
153 txController.Commit();
154 }
155
156 }
157 }
158
159
160 /// <summary>
161 /// Release the resource held by the serviced components
162 /// </summary>
163 /// <param name="txControllers">ITransactionController array</param>
164 public static void DisposeAll(params object[] txControllers)
165 {
166 foreach (object txController in txControllers)
167 {
168 if (txController != null)
169 {
170 try
171 {
172 //check is txController is a service compnen.
173 if (txController is System.EnterpriseServices.ServicedComponent)
174 {
175 //destory the serviced component
176 ((ServicedComponent)txController).Dispose();
177 }
178 }
179 catch (Exception ex){}
180 }
181 }
182 }
183 }
184
185 /// <summary>
186 /// Transaction controller that supports transaction.
187 /// </summary>
188 [ProgId("SupportTransaction")]
189 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991112")]
190 [Transaction(System.EnterpriseServices.TransactionOption.Supported)]
191 public class SupportTransaction : TransactionControllerBase
192 {
193 public SupportTransaction()
194 {
195 }
196 }
197
198
199 /// <summary>
200 /// Transaction controller that requires transaction
201 /// </summary>
202 [ProgId("RequireTransaction")]
203 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991113")]
204 [Transaction(System.EnterpriseServices.TransactionOption.Required)]
205 public class RequireTransaction : TransactionControllerBase
206 {
207 public RequireTransaction()
208 {
209 }
210
211
212 }
213
214 /// <summary>
215 /// Transaction controller that requires new transaction
216 /// </summary>
217 [ProgId("RequireNewTransaction")]
218 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991114")]
219 [Transaction(System.EnterpriseServices.TransactionOption.RequiresNew,Isolation=TransactionIsolationLevel.ReadCommitted)]
220 public class RequireNewTransaction : TransactionControllerBase
221 {
222 public RequireNewTransaction()
223 {
224 }
225 }
226
227 /// <summary>
228 /// Transaction controller that doesn't support transaction
229 /// </summary>
230 [ProgId("NoTransaction")]
231 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991115")]
232 [Transaction(System.EnterpriseServices.TransactionOption.NotSupported)]
233 public class NoTransaction : TransactionControllerBase
234 {
235 public NoTransaction()
236 {
237 }
238 }
239 }
240
2 using System.EnterpriseServices;
3 using System.Runtime.InteropServices;
4 using System.Reflection;
5
6 [assembly: ApplicationActivation(ActivationOption.Library)]
7 [assembly: ApplicationID("77769CB1-A707-11D0-989D-00C04FD444E4")]
8 [assembly: ApplicationName("SAF.Transaction")]
9 namespace MyControl.SAFApplication
10 {
11 /// <summary>
12 /// Interface each transaction controller must implement.
13 /// </summary>
14 public interface ITransactionController
15 {
16 object ExecuteMethod(object o, string method, params object[] p);
17 void Rollback();
18 void Commit();
19 }
20
21 /// <summary>
22 /// TransactionControllerBase is the base class for serviced components in SAF.Transaction.
23 /// It provides a way to execute business method as part of the transaction context and abilities
24 /// to commit and rollback transactions.
25 /// </summary>
26 public abstract class TransactionControllerBase : System.EnterpriseServices.ServicedComponent,ITransactionController
27 {
28
29 public virtual object ExecuteMethod(object o, string method, params object[] p )
30 {
31 try
32 {
33 //use the reflection to invoke the business method within the current transaction scope.
34 return o.GetType().InvokeMember(method,BindingFlags.InvokeMethod,null,o,p);
35 }
36 catch (Exception ex)
37 {
38 //if exception occurs, mark the current transaction as such so that we can
39 //rollback the transaction later.
40 if (ContextUtil.IsInTransaction)
41 {
42 ContextUtil.DisableCommit();
43 }
44 //rethow the exception to notify the caller.
45 throw ex;
46 }
47 }
48
49 /// <summary>
50 /// Rollback method set abort the current transaction.
51 /// </summary>
52 public virtual void Rollback()
53 {
54 //if it is part of a transaction, abort it.
55 if (ContextUtil.IsInTransaction)
56 {
57 ContextUtil.SetAbort();
58 }
59 }
60
61 /// <summary>
62 /// Commit method commit the current transaction if all the transaction vode
63 /// are good.
64 /// </summary>
65 public virtual void Commit()
66 {
67 //check if it is in a transaction
68 if (ContextUtil.IsInTransaction)
69 {
70 //check if the transaction vote is good. if so, set complete on the transaction
71 //otherwise, abort the transaction.
72 if (ContextUtil.MyTransactionVote == TransactionVote.Commit)
73 {
74 ContextUtil.SetComplete();
75 }
76 else
77 {
78 ContextUtil.SetAbort();
79 }
80 }
81 }
82 }
83
84
85 /// <summary>
86 /// Provide the Manager class that
87 /// clients interact when creating different type of transaction compnent.
88 /// </summary>
89 public class TransactionManager
90 {
91 /// <summary>
92 /// Return a new serviced component that supports transaction
93 /// </summary>
94 /// <returns>SupportTransaction object</returns>
95 public static ITransactionController GetSupportTransactionController()
96 {
97 return new SupportTransaction();
98 }
99
100 /// <summary>
101 /// Return a new service component that require transaction
102 /// </summary>
103 /// <returns>RequireTransaction object</returns>
104 public static ITransactionController GetRequireTransactionController()
105 {
106 return new RequireTransaction();
107 }
108
109 /// <summary>
110 /// Return a new service component that require new transaction
111 /// </summary>
112 /// <returns>RequireNewTransaction object</returns>
113 public static ITransactionController GetRequireNewTransactionController()
114 {
115 return new RequireNewTransaction();
116 }
117
118 /// <summary>
119 /// Return a new service component with no transaction
120 /// </summary>
121 /// <returns>NoTransaction object</returns>
122 public static ITransactionController GetNoTransactionController()
123 {
124 return new NoTransaction();
125 }
126
127 /// <summary>
128 /// Helper method that will rollback array of ITransactionController objects
129 /// </summary>
130 /// <param name="txControllers">ITransactionController array</param>
131 public static void Rollback(params ITransactionController[] txControllers)
132 {
133 foreach (ITransactionController txController in txControllers)
134 {
135 if (txController != null)
136 {
137 txController.Rollback();
138 }
139
140 }
141 }
142
143 /// <summary>
144 /// Helper method that will commit array of ITransactionController objects
145 /// </summary>
146 /// <param name="txControllers">ITransactionController array</param>
147 public static void Commit(params ITransactionController[] txControllers)
148 {
149 foreach (ITransactionController txController in txControllers)
150 {
151 if (txController != null)
152 {
153 txController.Commit();
154 }
155
156 }
157 }
158
159
160 /// <summary>
161 /// Release the resource held by the serviced components
162 /// </summary>
163 /// <param name="txControllers">ITransactionController array</param>
164 public static void DisposeAll(params object[] txControllers)
165 {
166 foreach (object txController in txControllers)
167 {
168 if (txController != null)
169 {
170 try
171 {
172 //check is txController is a service compnen.
173 if (txController is System.EnterpriseServices.ServicedComponent)
174 {
175 //destory the serviced component
176 ((ServicedComponent)txController).Dispose();
177 }
178 }
179 catch (Exception ex){}
180 }
181 }
182 }
183 }
184
185 /// <summary>
186 /// Transaction controller that supports transaction.
187 /// </summary>
188 [ProgId("SupportTransaction")]
189 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991112")]
190 [Transaction(System.EnterpriseServices.TransactionOption.Supported)]
191 public class SupportTransaction : TransactionControllerBase
192 {
193 public SupportTransaction()
194 {
195 }
196 }
197
198
199 /// <summary>
200 /// Transaction controller that requires transaction
201 /// </summary>
202 [ProgId("RequireTransaction")]
203 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991113")]
204 [Transaction(System.EnterpriseServices.TransactionOption.Required)]
205 public class RequireTransaction : TransactionControllerBase
206 {
207 public RequireTransaction()
208 {
209 }
210
211
212 }
213
214 /// <summary>
215 /// Transaction controller that requires new transaction
216 /// </summary>
217 [ProgId("RequireNewTransaction")]
218 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991114")]
219 [Transaction(System.EnterpriseServices.TransactionOption.RequiresNew,Isolation=TransactionIsolationLevel.ReadCommitted)]
220 public class RequireNewTransaction : TransactionControllerBase
221 {
222 public RequireNewTransaction()
223 {
224 }
225 }
226
227 /// <summary>
228 /// Transaction controller that doesn't support transaction
229 /// </summary>
230 [ProgId("NoTransaction")]
231 [Guid("E42F5FFF-823B-4F20-AE80-B13A3C991115")]
232 [Transaction(System.EnterpriseServices.TransactionOption.NotSupported)]
233 public class NoTransaction : TransactionControllerBase
234 {
235 public NoTransaction()
236 {
237 }
238 }
239 }
240
下面提供一个事务处理类的测试实例:具体如下
1 using System;
2 using System.Reflection;
3 //using SAF.Transaction;
4 using System.Data;
5 using System.Data.SqlClient;
6
7 namespace MyControl.SAFApplication
8 {
9 /// <summary>
10 /// Demo that show SAF.Transaction can be used wrap multiple
11 /// calls into different transactions
12 /// </summary>
13 class Class1
14 {
15
16 //[STAThread]
17 static void TestMain(string[] args)
18 {
19 DataAccess data = new DataAccess();
20 //clean up the table
21 data.ClearupTable();
22
23 //--------------Sample 1--------------------------------//
24 ITransactionController transaction_A= TransactionManager.GetRequireTransactionController();
25 try
26 {
27 transaction_A.ExecuteMethod(data,"AddNewRecord",new object[2]{"xin","111111111"});
28 transaction_A.ExecuteMethod(data,"AddNewRecord",new object[2]{"mike","222222222"});
29 //this call will fail due to duplicate key error.
30 transaction_A.ExecuteMethod(data,"AddNewRecord",new object[2]{"john","111111111"});
31 TransactionManager.Commit(transaction_A);
32 }
33 catch (Exception ex)
34 {
35 TransactionManager.Rollback(transaction_A);
36 //additional error handling code.
37 }
38 finally
39 {
40 //release the resource used by the serviced component
41 TransactionManager.DisposeAll(transaction_A);
42 }
43
44 //--------------Sample 1 result --------------------------//
45 //None of three record is inserted to the employee table. //
46 //--------------------------------------------------------//
47
48 //clean up the table
49 data.ClearupTable();
50
51 //--------------Sample 2----------------------------------//
52 ITransactionController transaction_C= TransactionManager.GetRequireNewTransactionController();
53 ITransactionController transaction_B= TransactionManager.GetRequireTransactionController();
54
55 try
56 {
57 transaction_B.ExecuteMethod(data,"AddNewRecord","xin","111111111");
58 transaction_B.ExecuteMethod(data,"AddNewRecord","mike ","222222222");
59 try
60 {
61 //add an important employee. Add him regardless whether other
62 //employees are added to table successfully
63 transaction_C.ExecuteMethod(data,"AddNewRecord","bill","333333333");
64 TransactionManager.Commit(transaction_C);
65 }
66 catch (Exception ex)
67 {
68 TransactionManager.Rollback(transaction_C);
69 }
70 //this call will fail due to duplicate key error.
71 transaction_B.ExecuteMethod(data,"AddNewRecord",new object[2]{"john","111111111"});
72 TransactionManager.Commit(transaction_B);
73 }
74 catch (Exception ex)
75 {
76 TransactionManager.Rollback(transaction_B);
77 //additional error handling code.
78 }
79 finally
80 {
81 //release the resource used by the serviced component
82 TransactionManager.DisposeAll(transaction_B,transaction_C);
83 }
84
85 //--------------Sample 2 result ---------------------------//
86 //----------Only bill is added to the employee table.------//
87 //---------------------------------------------------------//
88
89
90 //clean up the table
91 data.ClearupTable();
92
93 //--------------Sample 3-----------------------------------//
94 ITransactionController transaction_D= TransactionManager.GetNoTransactionController();
95 ITransactionController transaction_E= TransactionManager.GetSupportTransactionController();
96 ITransactionController transaction_F= TransactionManager.GetRequireTransactionController();
97 try
98 {
99 data.AddNewRecord("xin","111111111");
100 transaction_D.ExecuteMethod(data,"AddNewRecord","mike","222222222");
101 transaction_E.ExecuteMethod(data,"AddNewRecord","bill","333333333");
102 //this call will fail due to duplicate key error.
103 transaction_F.ExecuteMethod(data,"AddNewRecord","john","111111111");
104 TransactionManager.Commit(transaction_D,transaction_E,transaction_F);
105 }
106 catch (Exception ex)
107 {
108 TransactionManager.Rollback(transaction_D,transaction_E,transaction_F);
109 //additional error handling code.
110 }
111 finally
112 {
113 //release the resource used by the serviced component
114 TransactionManager.DisposeAll(transaction_D,transaction_E,transaction_F);
115 }
116
117 //--------------Sample 3 result --------------------------------------------//
118 //only xin, mike, bill are added to the employee table. John is not added.--//
119 //--------------------------------------------------------------------------//
120
121 }
122
123 }
124 /// <summary>
125 /// DataAccess provides access to testing db.
126 /// </summary>
127 public class DataAccess
128 {
129 private string connection;
130 public DataAccess()
131 {
132 connection ="Initial Catalog=SAFDemo;Data Source=localhost;Integrated Security=SSPI";
133 }
134 /// <summary>
135 /// Insert a record to the table
136 /// </summary>
137 /// <param name="name"></param>
138 /// <param name="ssn"></param>
139 public void AddNewRecord(string name,string ssn)
140 {
141
142 SqlConnection conn = new SqlConnection(connection);
143 try
144 {
145 conn.Open();
146 SqlCommand command = new SqlCommand("insert into employees values('" + name + "','" + ssn + "')",conn);
147 command.ExecuteNonQuery();
148 }
149 finally
150 {
151 conn.Close();
152 }
153
154 }
155
156 /// <summary>
157 /// Clearn up the table for the next test
158 /// </summary>
159 public void ClearupTable()
160 {
161 SqlConnection conn = new SqlConnection(connection);
162 try
163 {
164 conn.Open();
165 SqlCommand command = new SqlCommand("delete from employees",conn);
166 command.ExecuteNonQuery();
167 }
168 finally
169 {
170 conn.Close();
171 }
172 }
173 }
174 }
175
2 using System.Reflection;
3 //using SAF.Transaction;
4 using System.Data;
5 using System.Data.SqlClient;
6
7 namespace MyControl.SAFApplication
8 {
9 /// <summary>
10 /// Demo that show SAF.Transaction can be used wrap multiple
11 /// calls into different transactions
12 /// </summary>
13 class Class1
14 {
15
16 //[STAThread]
17 static void TestMain(string[] args)
18 {
19 DataAccess data = new DataAccess();
20 //clean up the table
21 data.ClearupTable();
22
23 //--------------Sample 1--------------------------------//
24 ITransactionController transaction_A= TransactionManager.GetRequireTransactionController();
25 try
26 {
27 transaction_A.ExecuteMethod(data,"AddNewRecord",new object[2]{"xin","111111111"});
28 transaction_A.ExecuteMethod(data,"AddNewRecord",new object[2]{"mike","222222222"});
29 //this call will fail due to duplicate key error.
30 transaction_A.ExecuteMethod(data,"AddNewRecord",new object[2]{"john","111111111"});
31 TransactionManager.Commit(transaction_A);
32 }
33 catch (Exception ex)
34 {
35 TransactionManager.Rollback(transaction_A);
36 //additional error handling code.
37 }
38 finally
39 {
40 //release the resource used by the serviced component
41 TransactionManager.DisposeAll(transaction_A);
42 }
43
44 //--------------Sample 1 result --------------------------//
45 //None of three record is inserted to the employee table. //
46 //--------------------------------------------------------//
47
48 //clean up the table
49 data.ClearupTable();
50
51 //--------------Sample 2----------------------------------//
52 ITransactionController transaction_C= TransactionManager.GetRequireNewTransactionController();
53 ITransactionController transaction_B= TransactionManager.GetRequireTransactionController();
54
55 try
56 {
57 transaction_B.ExecuteMethod(data,"AddNewRecord","xin","111111111");
58 transaction_B.ExecuteMethod(data,"AddNewRecord","mike ","222222222");
59 try
60 {
61 //add an important employee. Add him regardless whether other
62 //employees are added to table successfully
63 transaction_C.ExecuteMethod(data,"AddNewRecord","bill","333333333");
64 TransactionManager.Commit(transaction_C);
65 }
66 catch (Exception ex)
67 {
68 TransactionManager.Rollback(transaction_C);
69 }
70 //this call will fail due to duplicate key error.
71 transaction_B.ExecuteMethod(data,"AddNewRecord",new object[2]{"john","111111111"});
72 TransactionManager.Commit(transaction_B);
73 }
74 catch (Exception ex)
75 {
76 TransactionManager.Rollback(transaction_B);
77 //additional error handling code.
78 }
79 finally
80 {
81 //release the resource used by the serviced component
82 TransactionManager.DisposeAll(transaction_B,transaction_C);
83 }
84
85 //--------------Sample 2 result ---------------------------//
86 //----------Only bill is added to the employee table.------//
87 //---------------------------------------------------------//
88
89
90 //clean up the table
91 data.ClearupTable();
92
93 //--------------Sample 3-----------------------------------//
94 ITransactionController transaction_D= TransactionManager.GetNoTransactionController();
95 ITransactionController transaction_E= TransactionManager.GetSupportTransactionController();
96 ITransactionController transaction_F= TransactionManager.GetRequireTransactionController();
97 try
98 {
99 data.AddNewRecord("xin","111111111");
100 transaction_D.ExecuteMethod(data,"AddNewRecord","mike","222222222");
101 transaction_E.ExecuteMethod(data,"AddNewRecord","bill","333333333");
102 //this call will fail due to duplicate key error.
103 transaction_F.ExecuteMethod(data,"AddNewRecord","john","111111111");
104 TransactionManager.Commit(transaction_D,transaction_E,transaction_F);
105 }
106 catch (Exception ex)
107 {
108 TransactionManager.Rollback(transaction_D,transaction_E,transaction_F);
109 //additional error handling code.
110 }
111 finally
112 {
113 //release the resource used by the serviced component
114 TransactionManager.DisposeAll(transaction_D,transaction_E,transaction_F);
115 }
116
117 //--------------Sample 3 result --------------------------------------------//
118 //only xin, mike, bill are added to the employee table. John is not added.--//
119 //--------------------------------------------------------------------------//
120
121 }
122
123 }
124 /// <summary>
125 /// DataAccess provides access to testing db.
126 /// </summary>
127 public class DataAccess
128 {
129 private string connection;
130 public DataAccess()
131 {
132 connection ="Initial Catalog=SAFDemo;Data Source=localhost;Integrated Security=SSPI";
133 }
134 /// <summary>
135 /// Insert a record to the table
136 /// </summary>
137 /// <param name="name"></param>
138 /// <param name="ssn"></param>
139 public void AddNewRecord(string name,string ssn)
140 {
141
142 SqlConnection conn = new SqlConnection(connection);
143 try
144 {
145 conn.Open();
146 SqlCommand command = new SqlCommand("insert into employees values('" + name + "','" + ssn + "')",conn);
147 command.ExecuteNonQuery();
148 }
149 finally
150 {
151 conn.Close();
152 }
153
154 }
155
156 /// <summary>
157 /// Clearn up the table for the next test
158 /// </summary>
159 public void ClearupTable()
160 {
161 SqlConnection conn = new SqlConnection(connection);
162 try
163 {
164 conn.Open();
165 SqlCommand command = new SqlCommand("delete from employees",conn);
166 command.ExecuteNonQuery();
167 }
168 finally
169 {
170 conn.Close();
171 }
172 }
173 }
174 }
175