1
1
using System ;
2
2
using System . Collections ;
3
+ using System . Threading ;
3
4
using System . Transactions ;
4
5
using NHibernate . Engine ;
5
6
using NHibernate . Engine . Transaction ;
@@ -26,57 +27,19 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
26
27
{
27
28
if ( session . TransactionContext != null )
28
29
return ;
29
-
30
- if ( System . Transactions . Transaction . Current == null )
31
- return ;
32
-
33
- var transactionContext = new DistributedTransactionContext ( session ,
34
- System . Transactions . Transaction . Current ) ;
35
- session . TransactionContext = transactionContext ;
36
- logger . DebugFormat ( "enlisted into DTC transaction: {0}" ,
37
- transactionContext . AmbientTransation . IsolationLevel ) ;
38
- session . AfterTransactionBegin ( null ) ;
39
-
40
- TransactionCompletedEventHandler handler = null ;
41
-
42
- handler = delegate ( object sender , TransactionEventArgs e )
43
- {
44
- using ( new SessionIdLoggingContext ( session . SessionId ) )
45
- {
46
- ( ( DistributedTransactionContext ) session . TransactionContext ) . IsInActiveTransaction = false ;
47
-
48
- bool wasSuccessful = false ;
49
- try
50
- {
51
- wasSuccessful = e . Transaction . TransactionInformation . Status
52
- == TransactionStatus . Committed ;
53
- }
54
- catch ( ObjectDisposedException ode )
55
- {
56
- logger . Warn ( "Completed transaction was disposed, assuming transaction rollback" , ode ) ;
57
- }
58
- session . AfterTransactionCompletion ( wasSuccessful , null ) ;
59
- if ( transactionContext . ShouldCloseSessionOnDistributedTransactionCompleted )
60
- {
61
- session . CloseSessionFromDistributedTransaction ( ) ;
62
- }
63
- session . TransactionContext = null ;
64
- }
65
30
66
- e . Transaction . TransactionCompleted -= handler ;
67
- } ;
68
-
69
- transactionContext . AmbientTransation . TransactionCompleted += handler ;
31
+ var transaction = System . Transactions . Transaction . Current ;
32
+ if ( transaction == null )
33
+ return ;
70
34
71
- transactionContext . AmbientTransation . EnlistVolatile ( transactionContext ,
72
- EnlistmentOptions . EnlistDuringPrepareRequired ) ;
35
+ session . TransactionContext = new DistributedTransactionContext ( session , transaction ) ;
36
+ logger . DebugFormat ( "enlisted into DTC transaction: {0}" , transaction . IsolationLevel . ToString ( ) ) ;
37
+ session . AfterTransactionBegin ( null ) ;
73
38
}
74
39
75
40
public bool IsInDistributedActiveTransaction ( ISessionImplementor session )
76
41
{
77
- var distributedTransactionContext = ( ( DistributedTransactionContext ) session . TransactionContext ) ;
78
- return distributedTransactionContext != null &&
79
- distributedTransactionContext . IsInActiveTransaction ;
42
+ return session . TransactionContext != null ;
80
43
}
81
44
82
45
public void ExecuteWorkInIsolation ( ISessionImplementor session , IIsolatedWork work , bool transacted )
@@ -92,35 +55,37 @@ public void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork wo
92
55
93
56
public class DistributedTransactionContext : ITransactionContext , IEnlistmentNotification
94
57
{
95
- public System . Transactions . Transaction AmbientTransation { get ; set ; }
58
+ System . Transactions . Transaction _transaction ;
59
+
60
+ ISessionImplementor _session ;
61
+
96
62
public bool ShouldCloseSessionOnDistributedTransactionCompleted { get ; set ; }
97
- private readonly ISessionImplementor sessionImplementor ;
98
- public bool IsInActiveTransaction ;
99
63
100
- public DistributedTransactionContext ( ISessionImplementor sessionImplementor , System . Transactions . Transaction transaction )
64
+ public DistributedTransactionContext ( ISessionImplementor session , System . Transactions . Transaction transaction )
101
65
{
102
- this . sessionImplementor = sessionImplementor ;
103
- AmbientTransation = transaction . Clone ( ) ;
104
- IsInActiveTransaction = true ;
66
+ _session = session ;
67
+ _transaction = transaction . Clone ( ) ;
68
+ _transaction . EnlistVolatile ( this , EnlistmentOptions . EnlistDuringPrepareRequired ) ;
105
69
}
106
70
107
- #region IEnlistmentNotification Members
108
-
109
71
void IEnlistmentNotification . Prepare ( PreparingEnlistment preparingEnlistment )
110
72
{
111
- using ( new SessionIdLoggingContext ( sessionImplementor . SessionId ) )
73
+ using ( new SessionIdLoggingContext ( _session . SessionId ) )
112
74
{
113
75
try
114
76
{
115
- using ( var tx = new TransactionScope ( AmbientTransation ) )
77
+ using ( var tx = new TransactionScope ( _transaction ) )
116
78
{
117
- sessionImplementor . BeforeTransactionCompletion ( null ) ;
118
- if ( sessionImplementor . FlushMode != FlushMode . Never && sessionImplementor . ConnectionManager . IsConnected )
79
+ _session . BeforeTransactionCompletion ( null ) ;
80
+ if ( _session . FlushMode != FlushMode . Never && _session . ConnectionManager . IsConnected )
119
81
{
120
- using ( sessionImplementor . ConnectionManager . FlushingFromDtcTransaction )
82
+ using ( _session . ConnectionManager . FlushingFromDtcTransaction )
121
83
{
122
- logger . Debug ( string . Format ( "[session-id={0}] Flushing from Dtc Transaction" , sessionImplementor . SessionId ) ) ;
123
- sessionImplementor . Flush ( ) ;
84
+ logger . Debug (
85
+ string . Format (
86
+ "[session-id={0}] Flushing from Dtc Transaction" ,
87
+ _session . SessionId . ToString ( ) ) ) ;
88
+ _session . Flush ( ) ;
124
89
}
125
90
}
126
91
logger . Debug ( "prepared for DTC transaction" ) ;
@@ -131,53 +96,105 @@ void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
131
96
}
132
97
catch ( Exception exception )
133
98
{
134
- logger . Error ( "DTC transaction prepare phase failed" , exception ) ;
135
- preparingEnlistment . ForceRollback ( exception ) ;
99
+ using ( this )
100
+ {
101
+ try
102
+ {
103
+ logger . Error ( "DTC transaction prepare phase failed" , exception ) ;
104
+ OnTransactionCompleted ( false ) ;
105
+ }
106
+ catch ( Exception e )
107
+ {
108
+ logger . Warn ( "Issue preparing DTC transaction" , e ) ;
109
+ }
110
+ finally
111
+ {
112
+ preparingEnlistment . ForceRollback ( exception ) ;
113
+ }
114
+ }
136
115
}
137
116
}
138
117
}
139
118
140
119
void IEnlistmentNotification . Commit ( Enlistment enlistment )
141
120
{
142
- using ( new SessionIdLoggingContext ( sessionImplementor . SessionId ) )
121
+ using ( new SessionIdLoggingContext ( _session . SessionId ) )
122
+ using ( this )
143
123
{
144
- logger . Debug ( "committing DTC transaction" ) ;
145
- // we have nothing to do here, since it is the actual
146
- // DB connection that will commit the transaction
147
- enlistment . Done ( ) ;
148
- IsInActiveTransaction = false ;
124
+ try
125
+ {
126
+ logger . Debug ( "Committing DTC transaction" ) ;
127
+ OnTransactionCompleted ( true ) ;
128
+ }
129
+ catch ( Exception e )
130
+ {
131
+ logger . Warn ( "Exception happened at DTC transaction commit phase" , e ) ;
132
+ }
133
+ finally
134
+ {
135
+ enlistment . Done ( ) ;
136
+ }
149
137
}
150
138
}
151
139
152
140
void IEnlistmentNotification . Rollback ( Enlistment enlistment )
153
141
{
154
- using ( new SessionIdLoggingContext ( sessionImplementor . SessionId ) )
142
+ using ( new SessionIdLoggingContext ( _session . SessionId ) )
143
+ using ( this )
155
144
{
156
- logger . Debug ( "rolled back DTC transaction" ) ;
157
- // Currently AfterTransactionCompletion is called by the handler for the TransactionCompleted event.
158
- //sessionImplementor.AfterTransactionCompletion(false, null);
159
- enlistment . Done ( ) ;
160
- IsInActiveTransaction = false ;
145
+ try
146
+ {
147
+ logger . Debug ( "Rolled back DTC transaction" ) ;
148
+ OnTransactionCompleted ( false ) ;
149
+ }
150
+ catch ( Exception e )
151
+ {
152
+ logger . Warn ( "Exception happened at DTC transaction rollback phase" , e ) ;
153
+ }
154
+ finally
155
+ {
156
+ enlistment . Done ( ) ;
157
+ }
161
158
}
162
159
}
163
160
164
161
void IEnlistmentNotification . InDoubt ( Enlistment enlistment )
165
162
{
166
- using ( new SessionIdLoggingContext ( sessionImplementor . SessionId ) )
163
+ using ( new SessionIdLoggingContext ( _session . SessionId ) )
164
+ using ( this )
167
165
{
168
- sessionImplementor . AfterTransactionCompletion ( false , null ) ;
169
- logger . Debug ( "DTC transaction is in doubt" ) ;
170
- enlistment . Done ( ) ;
171
- IsInActiveTransaction = false ;
166
+ try
167
+ {
168
+ logger . Debug ( "DTC transaction is in doubt" ) ;
169
+ OnTransactionCompleted ( false ) ;
170
+ }
171
+ catch ( Exception e )
172
+ {
173
+ logger . Warn ( "Exception happened at DTC transaction in doubt phase" , e ) ;
174
+ }
175
+ finally
176
+ {
177
+ enlistment . Done ( ) ;
178
+ }
172
179
}
173
180
}
174
181
175
- #endregion
176
-
177
182
public void Dispose ( )
178
183
{
179
- if ( AmbientTransation != null )
180
- AmbientTransation . Dispose ( ) ;
184
+ if ( _transaction != null )
185
+ _transaction . Dispose ( ) ;
186
+ _transaction = null ;
187
+ if ( _session != null )
188
+ _session . TransactionContext = null ;
189
+ _session = null ;
190
+ }
191
+
192
+ void OnTransactionCompleted ( bool successful )
193
+ {
194
+ _session . TransactionContext = null ;
195
+ _session . AfterTransactionCompletion ( successful , null ) ;
196
+ if ( ShouldCloseSessionOnDistributedTransactionCompleted )
197
+ _session . CloseSessionFromDistributedTransaction ( ) ;
181
198
}
182
199
}
183
200
}
0 commit comments