Insist on learning WF Article Index
1. a transaction is not successful or failed when you make a group of updates. It is impossible to only partially update the transaction. The most typical application of transactions is in relational databases. Compensation is an operation that has been successfully canceled. In our workflow, we may complete a task consisting of many activities. For example, our activities all use transactionscopeactivity, and we will find an error later, if you want to cancel a successful operation, it has nothing to do with the transaction, because the transaction has been successful. In this case, we can use compensation. You can logically divide a group of activities and specify a compensation processor for this group of activities. In the compensation processor, you declare that if the compensation is successful, the group will be executed. The compensation processor automatically tracks exceptions. Or we can directly use compensateactivity.
The transaction can be rolled back automatically, but the compensation is not. The compensation only provides a place for you to cancel the work, but the specificCodeYou can implement it on your own. WF implements the icompensatableactivity interface, which can be compensated. WF provides two compensatabletransactionscopeactivity
, Compensatablesequenceactivity. The previous activity supports transactions and compensation. Compensatablehandleractivity is the container for your compensation. You can also explicitly use compensateactivity, which allows you to use its targetactivityname to specify compensation for an activity. However, this activity can only be added to compensationhandleactivity, faulthandleractivity, and cancellationhandleractivity.
Ii. Here is a specific example to illustrate if compensation is used. If you plan to travel, you will first set a train ticket before departure and then set a hotel. If you have set a train ticket, but when you decide a hotel, you will find that all the hotels have been booked by others. At this time, the train ticket you set is useless, I had to unsubscribe. In ourProgramWe use compensation to complete this function. Is the workflow we designed:
The procedure is as follows: first reserve a train ticket and then reserve a hotel. When booking a hotel, we will determine whether the ticket is successful. If it fails, an exception is thrown. The ticket booking activity (bookticket) is included in the compensatabletransactionscopeactivity activity. The compensation process is as follows:
When booking a hotel, if the reservation fails, we will use the bookfail (throwactivity) activity in to throw an exception. The following is a custom exception class. The Code is as follows:
Using System; Using System. Collections. Generic; Using System. LINQ; Using System. text; Using System. runtime. serialization; Namespace Carycompensationdemo {[ Serializableattribute ()] Public class Booktransaction exception : Exception { Public Book1_exception (): Base (){} Public Bookexcepexception ( String Message ): Base (Message ){} Public Bookexcepexception ( String Message,Exception Innerexception)
: Base (Message, innerexception ){} Protected Bookexcepexception ( Serializationinfo Info, Streamingcontext Context)
: Base (Info, context ){}}}
Capture exceptions in the error handling program of the entire job and perform compensation, for example:
We use the targetactivityname attribute of the compensateactivity activity to specify compensation for an activity.
The code for the entire workflow is as follows:
Using System; Using System. componentmodel; Using System. componentmodel. design; Using System. collections; Using System. drawing; Using System. LINQ; Using System. workflow. componentmodel. compiler; Using System. workflow. componentmodel. serialization; Using System. workflow. componentmodel; Using System. workflow. componentmodel. design; Using System. workflow. runtime; Using System. workflow. Activities;Using System. workflow. Activities. Rules; Namespace Carycompensationdemo { Public sealed partial class Carytourworkflow : Sequentialworkflowactivity { Public Booktransaction exception Discontinuedproductexception1 = New Booktransaction exception (); Public Carytourworkflow () {initializecomponent ();} Private void Tourstart_executecode ( Object Sender, Eventargs E ){ Console . Writeline ( "Preparing for a tour" );} Private void Bookticket_executecode ( Object Sender, Eventargs E ){ Console . Writeline ( "Reserve a train ticket" );} Private void Cancelticket_executecode ( Object Sender, Eventargs E ){ Console . Writeline ( "Annealing ticket" );} Private void Bookhotelok_executecode ( Object Sender, Eventargs E ){ Console . Writeline ( "Hotel Reservation successful" );} Private void Bookok_condition ( Object Sender, Conditionaleventargs E) {e. Result = False ;} Private void Bookexception_executecode ( Object Sender, Eventargs E ){ Console . Writeline ( "No hotel booked" );}}}
3. To use compensation, we need to load the persistence service in the Host Program. The following is the code of the Host Program:
Using System; Using System. Collections. Generic; Using System. LINQ;Using System. text; Using System. Threading; Using System. workflow. runtime; Using System. workflow. runtime. Hosting; Namespace Carycompensationdemo { Class Program { Static Autoresetevent Waithandle = New Autoresetevent ( False );Static void Main (){ Using ( Workflowruntime Workflowruntime = New Workflowruntime ()){ Try { Const string Connectstring = "Initial catalog = workflowpersistence;
Data Source = localhost; Integrated Security = sspi ;" ; Workflowruntime. addservice ( New Sqlworkflowpersistenceservice (Connectstring); workflowruntime. workflowcompleted + = onworkflowcompleted; workflowruntime. workflowterminated + = onworkflowterminated; workflowruntime. workflowaborted + = worker; workflowruntime. startruntime (); Type Type = Typeof (Carycompensationdemo. Carytourworkflow ); Workflowruntime. createworkflow (type). Start (); waithandle. waitone ();} Catch ( Exception Ex ){ If (EX. innerexception! =Null ) Console . Writeline (ex. innerexception. Message ); Else Console . Writeline (ex. Message );} Finally {Workflowruntime. stopruntime ();}}} Static void Onworkflowaborted ( Object Sender, Workfloweventargs E ){ Console . Writeline ("Check whether the database connection is abnormal" ); Waithandle. Set ();} Static void Onworkflowcompleted ( Object Sender, Workflowcompletedeventargs E ){ Console . Writeline ( "Complete Workflow" ); Waithandle. Set ();} Static void Onworkflowterminated ( Object Sender, Workflowterminatedeventargs E ){ Console . Writeline (E. Exception. Message); waithandle. Set ();}}}
4. Finally, let's look at the running results: