Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 37 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
37
Dung lượng
552,54 KB
Nội dung
142 Part II Working with Activities 2. Click the View Fault Handlers button to activate the fault handlers visual designer. The View Fault Handlers button is the right button of the three-button group at the lower-left corner of the designer window. The designer should appear as you see here: 3. Select the FaultHandler activity from the Toolbox, drag it over the workflow designer’s fault handler surface, and drop it between the blue arrows. Your designer surface should now look like this: 4. As with other activities, we have some properties to set to make this fault handler fully operational. The first property we’ll set is the FaultT ype property. Select the FaultType Chapter 7 Basic Activity Operations 143 property in Visual Studio’s Properties pane, and click the browse button (the button with the three dots) to activate the Browse And Select A .NET Type dialog box. 5. With the Browse And Select A .NET Type dialog box active, select the Type tab if it’s not already selected and then expand the mscorlib tree node. From there, select System (for the System assembly) and scroll down the resulting list in the right pane until you find the list item Exception in the Type Name column. Select this by clicking the Exception line in the right pane’s ListView control. This places the text “System.Exception” in the Type Name edit control. Click OK to accept System.Exception as the exception type and dismiss the dialog box. You should find the value System.Exception has been assigned to the FaultT ype property. Note It’s no coincidence that the exception we’re asking this FaultHandler activity to use is the same as the exception type thrown by the Throw activity we used earlier in the chapter. They’re a matched set. If you don’t have a corresponding fault handler for a Throw activity in your workflow, keep in mind that if the exception is thrown at runtime, the WorkflowTerminated event is where you’ll soon find your workflow executing. If this isn’t what you want, add the appropriate FaultHandler activity. 144 Part II Working with Activities Note Although you see the Fault property in the preceding graphic, it’s actually disabled and therefore cannot be set. Ignore it. 6. So far, we’ve added a FaultHandler activity and we’ve told it what type of exception it will be handling, but we’ve not actually provided any code to deal with the exception if it’s thrown. To do that, drag a Code activity from the Toolbox and drop it into the area below where we dropped the FaultHandler activity itself. This area, identified by the name faultHandlerActivity1, is like a miniature workflow visual designer. So it readily accepts the Code activity, and as we’ve done with other instances of the Code activity, assign a value to its ExecuteCode property. In this case, type in OnException and press Enter. 7. Visual Studio then adds the OnException event handler to Workflow1 and opens the code editor for editing. To the OnException event handler, add this code: Console.WriteLine( "Exception handled within the workflow! The exception was: '{0}'", WorkflowException != null ? WorkflowException.Message : "Exception property not set, generic exception thrown"); Chapter 7 Basic Activity Operations 145 Note And again, it’s no coincidence we’re using the same WorkflowException property we used with the Throw activity. If the WorkflowException property is null, we’re directing Throw to simply throw a new instance of System.Exception. Otherwise, WorkflowException contains the exception to throw. 8. Now compile and execute the code. You should see this output: By using the FaultHandler, we’re able to process the exception (if we want to) and take any required actions. Note By throwing and handling exceptions at this level, your workflow instance is still essentially stopped. The advantage is that your workflow can work with the exception rather than throwing it to the workflow runtime to deal with. If you want to continue processing after specific exceptions are thrown (exceptions that you know you can recover from), don’t use Throw and FaultHandler activities to deal with them. Instead, use try/catch inside activity code so that the exception never leaks out to the runtime for disposition. If you can’t ade- quately handle the exception internally (using try/catch), resort to Throw and FaultHandler. Using the Suspend Activity Another housekeeping activity you might find useful under certain conditions is the Suspend activity. In fact, a common-use case is to handle a fault using FaultHandler and then suspend the activity using Suspend to signal human intervention is required. When you use the Suspend activity, you provide the activity with an error string through its Error property. This property can be bound to a dependency property (such as the Throw activity), a simple class property or field, or even a literal string (which we’ll do in the example to follow). When Suspend executes, the workflow runtime raises the WorkflowSuspended event and provides you with this error string in the event arguments. Putting a workflow instance into a suspended state means the instance is not currently executing, but neither is it unloaded. It’s essentially in a holding pattern, waiting for some action on your part. It’s also not considered idle, so automatic persistence doesn’t come into play here. Using the Suspend activity is relatively simple, as you’ll see. 146 Part II Working with Activities Note In a suspended state, your workflow instance is merely existing. It’s a good idea to hook the WorkflowSuspended event in your workflow-based applications so that you can take action when workflow instances enter the suspended state. At least then you’re notified they’ve been suspended, and you can take action to remove, resume, or restart them. Modifying our workflow to use the Suspend activity 1. With the ErrorThrower application again open in Visual Studio for editing, select the Workflow1.cs file in the ErrorFlow project and click the designer button to activate the workflow visual designer. (I again created a separate solution that targets this specific sec- tion. If you’re following along, continue using ErrorThrower. But if you haven’t completed the earlier steps in this chapter, you can jump straight to this point by opening the solu- tion in \Workflow\Chapter7\ErrorSuspender, or you can follow along with a completed version in \Workflow\Chapter7\ErrorSuspender Completed.) Because we’ll be adding the Suspend activity to the System.Exception fault handler we just added, select the fault handlers view by clicking the right-hand button at the bottom of the designer’s window. 2. From the Toolbox, drag an instance of the Suspend activity onto the fault handler’s design surface and place it after the Code activity, as shown here: 3. With the Suspend activity in place, select its Error property and type “This is an example suspension error ” (including the quotation marks) in the associated property edit control. Chapter 7 Basic Activity Operations 147 Tip Typing a literal string, as we’ve done here, is perfectly acceptable. However, you can also bind this to a string-based dependency property that is more easily altered as your workflow executes. Clicking the browse button (the button with the three dots you see in the graphic) activates the binding dialog box we saw in step 7 of the “Creating a workflow using the Throw activity” procedure. Simply follow the same basic steps as you did there. 4. Because we don’t have a WorkflowSuspended event handler in our main application, we need to edit the Program.cs file from the main application and add it. In the Main method, locate code to hook the existing event handlers and add the following: workflowRuntime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(workflowSuspended); 5. Because we’re using an event handler named workflowSuspended, we need to code that: static void workflowSuspended(object sender, WorkflowSuspendedEventArgs e) { Console.WriteLine("Workflow instance suspended, error: '{0}'.", e.Error); waitHandle.Set(); } 6. Compile the application by clicking Build, Build Solution from Visual Studio’s main menu and then press F5 or Ctrl+F5 to execute the application (after correcting any compilation errors). The program output should be similar to this: When you run this application, you should see the console output generated by the WorkflowSuspended event handler in our main application. But you can do more than simply write text to the console. You can take any other action appropriate for your process flow. Although you could resume the workflow instance processing from here, it’s generally not rec- ommended. For one thing, the entire activity that was processing will be skipped, leaving your workflow instance to resume processing at a later stage in its flow, which probably isn’t a good thing (what was skipped, and how do you account for it?). At the very least, however, you can cleanly remove the workflow instance from processing and apply any necessary cleanup code. As if exceptions and suspended workflow instances aren’t enough, you can, if you need to do so, terminate your workflow instance. Let’s see how. 148 Part II Working with Activities Using the Te r minate Activity There are times when things get so bad that you have no recourse but to kill off a workflow instance. Perhaps some data came back from an external process in a bad format or was oth- erwise miscalculated. Or the database server simply disappeared and you can’t move forward without it. Or well, hopefully, you see where this line of reasoning is going. WF provides us with a ready-made way to terminate our workflow instances through the Terminate activity. The Terminate activity is used in precisely the same way as the Suspend activity, and in fact its properties are identical. The difference is that when Terminate executes, all hope for your workflow instance continuing execution is lost. When Terminate executes, the workflow runtime fires the WorkflowTerminated event, just as if there were an unhandled exception. To tell the two situations apart is difficult when processing the WorkflowTerminated event. All you can really do is examine the WorkflowTermi- natedEventArgs and look at the Exception property. If the workflow instance was terminated using the Terminate activity, the exception type will be System.Workflow.Component- Model.WorkflowTerminatedException rather than some other (probably more common) exception type. Let’s see how we use Terminate activity in our workflow code. Modifying our workflow to use the Terminate activity 1. We’re again going to work with the ErrorThrower application in Visual Studio. (If you haven’t completed the earlier steps in this chapter, you can jump straight to this point by opening the solution in \Workflow\Chapter7\ErrorTerminator, or you can follow along with a completed version in \Workflow\Chapter7\ErrorTerminator Completed.) Once again, select the Workflow1.cs file in the ErrorFlow project and click the designer button to activate the workflow visual designer. We first need to remove the Suspend activity we added in the preceding section. Simply select it with a single mouse click, and press the Delete key. 2. From the Toolbox, drag an instance of the Terminate activity onto the fault handler’s design surface and place it after the Code activity after first deleting the Suspend activity you placed there previously. Chapter 7 Basic Activity Operations 149 3. With the Terminate activity in place, select its Error property and type “This is an example termination error ” (again with quotes) in the associated property edit control. Note The tip I provided in the preceding section holds true here as well. You can use a literal string, as we’re doing here, or you can bind the string to an activity field, property, or dependency property. 4. Compile the application by choosing Build Solution from Visual Studio’s Build menu. After correcting any compilation errors, press F5 or Ctrl+F5 to run it. If all goes as expected, you’ll see something like the following: Terminate, like Suspend, is a fairly simple activity, but a powerful one. You won’t often need it, but when things go so badly for your workflow that you can’t continue, Terminate is the best tool in the Toolbox. If you want to continue to the next chapter, keep Visual Studio 2005 running and turn to Chapter 8. If you suspended a workflow instance somewhere along the way in this chapter, resume it! (Just kidding ) If you want to stop, exit Visual Studio 2005 now, save your spot in the book, and close it. Terminate seems like a good alternative at this point 150 Part II Working with Activities Chapter 7 Quick Reference To Do This Use the Sequence activity SequenceActivity is a composite activity, and as such it acts as a drop site for other activities. Simply drag and drop an instance of the Sequence activity onto the workflow visual designer. Then drag and drop other activities onto Sequence- Activity as necessary to complete your workflow. Those activ- ities will be executed in the order they appear in the designer, from top to bottom. Use the Code activity With the visual workflow designer visible and active, drag an instance of the Code activity onto the surface and drop it into the workflow process as appropriate. Then provide an ExecuteCode method name in the Properties window. Populate that method with the code you want to execute. Use the Throw activity With the visual workflow designer visible and active, drag an instance of the Throw activity onto the surface and drop it into the workflow process as appropriate. Then assign the Fault and FaultT ype properties to provide the Throw activity with the exception to throw as well as the type of exception it should expect. Use the FaultHandler activity With the visual workflow designer visible and active, and with the Fault Handlers view showing, drag an instance of the FaultHandler activity onto the surface and drop it into the workflow process as appropriate. Then assign the FaultType property to assign the type of exception it will handle. Use the Suspend activity With the visual workflow designer visible and active, drag an instance of the Suspend activity onto the surface and drop it into the workflow process as appropriate. Then assign the Error property to assign the error string value it will report to the workflow runtime via the WorkflowSuspended event. Use the Term in at e activity With the visual workflow designer visible and active, drag an instance of the Ter mi na te activity onto the surface and drop it into the workflow process as appropriate. Then assign the Error property to assign the error string value it will report to the workflow runtime via the WorkflowTerminated event. 151 Chapter 8 Calling External Methods and Workflows After completing this chapter, you will be able to: ■ Build and call local data services that are external to your workflow ■ Understand how interfaces are used to communicate between the host process and your workflow ■ Use external methods designed to transfer data between you workflow and host application ■ Invoke additional workflows from within an executing workflow As I was writing the preceding chapters, I kept thinking to myself, “I can’t wait to get to the part where we return real data to the host application!” Why? Because as interesting as work- flow is, there is only so much you can do to demonstrate activities and workflows without returning something realistic to the executing application. Theoretically, there might be an infinite number of interesting workflow examples and demonstrations I could write that only processed initialization data (such as the postal code example you saw in Chapter 1, “Intro- ducing Microsoft Windows Workflow Foundation”). But things become far more interesting, and to be honest, far more realistic when we kick off a workflow that seeks and processes data from external sources and returns that data in some processed form to our application. So why not just crack open an object and start sending data into an executing workflow, or from an executing workflow to the host application? Actually, you can do this with existing technology outside Windows Workflow Foundation (WF) using some form of marshaled communications, such as .NET Remoting or an XML Web service. Marshaling, sometimes also called serialization, is a process whereby data is converted from its original form into a form suitable for transmission between different processes and even between different computers. Why mention marshaling? Because your workflow is executing on a different thread than your host process, and passing data between threads without proper marshaling is a recipe for disaster for reasons beyond the scope of this chapter. In fact, your workflow could be in a persisted state at the time you tried to send it data. It’s not on a different thread it’s not even executing. But wouldn’t a .NET Remoting connection or an XML Web service be considered excessive if we just want to pass data between our workflow and the host process that’s controlling it? Absolutely! And this is the premise of this chapter—how we can establish local communica- tions. We’ll be setting up the systems necessary to satisfy the thread data-marshaling [...]... executing workflow, can that workflow execute a second workflow? The answer is yes! There is an activity, InvokeWorkflow, that’s used to start a secondary workflow Let’s briefly take a look at this activity by way of an example We’ll create a new sample console application that starts a workflow that merely writes a message to the console After writing this message, the workflow instance starts a second workflow. .. set { _instanceID = value; } } public static WorkflowMVDataService CreateDataService( Guid instanceID, WorkflowRuntime workflowRuntime) { lock (_syncLock) { // If we're just starting, save a copy of the workflow // runtime reference if (_workflowRuntime == null) 168 Part II Working with Activities { // Save instance of the workflow runtime _workflowRuntime = workflowRuntime; } // if // If we're just starting,... this iteration // and must be updated workflowDataService.InstanceID = instanceID; } // else Chapter 8 Calling External Methods and Workflows return workflowDataService; } // lock } public static WorkflowMVDataService GetRegisteredWorkflowDataService(Guid instanceID) { lock (_syncLock) { WorkflowMVDataService workflowDataService = MVDataConnector.MVDataService; if (workflowDataService == null) { throw... the MVWorkflow solution Chapter 8 Calling External Methods and Workflows 173 10 Compile the MVWorkflow project by pressing Shift+F6 or by selecting Build MVWorkflow from the Visual Studio Build menu, and fix any compilation errors that might have occurred After you have a successful compilation, check to be sure the MVDataUpdate activity was added to the Visual Studio ToolBox To check, open Workflow1 .cs... the workflow runtime So events into and out of the workflow instance are brokered by the workflow runtime The workflow runtime must do this because your host application could be trying to send data to a workflow instance that has been persisted and removed from active execution Chapter 8 Calling External Methods and Workflows 161 Returning to our bridge, the connection class maintains a field the workflow. .. sequential workflow library project to the WorkflowInvoker solution by clicking File, Add, and then New Project from the Visual Studio menu and then choosing the Workflow project type and Sequential Workflow Library template in the Add New Project dialog box Name it Workflow1 Visual Studio adds the new library project and opens the workflow visual designer for editing Be sure to save the new workflow. .. object WorkflowMVDataService workflowDataService = MVDataConnector.MVDataService; if (workflowDataService == null) { // First time through, so create the data service and // hand it to the connector workflowDataService = new WorkflowMVDataService(instanceID); MVDataConnector.MVDataService = workflowDataService; } // if else { // The data service is static and already registered with // the workflow. .. Methods and Workflows 167 8 The final functional block we’ll add to our bridge service is a method to raise the “motor vehicle data update” event The workflow uses this method to fire a notification to the host that data is available for pickup: public void RaiseMVDataUpdateEvent() { if (_workflowRuntime == null) _workflowRuntime = new WorkflowRuntime(); // Load persisted workflow instances _workflowRuntime.GetWorkflow(_instanceID);... workflow runtime We’ll also add the bridge connector class we just created as a pluggable service so that the workflow has access to the data connection class Therefore, add this method following the property we added in step 3: public static WorkflowMVDataService CreateDataService(Guid instanceID, WorkflowRuntime workflowRuntime) { lock (_syncLock) { // If we're just starting, save a copy of the workflow. .. object WorkflowMVDataService workflowDataService = MVDataConnector.MVDataService; if (workflowDataService == null) { // First time through, so create the data service and // hand it to the connector workflowDataService = new WorkflowMVDataService(instanceID); MVDataConnector.MVDataService = workflowDataService; } // if else { // The data service is static and already registered // with the workflow . add the following: workflowRuntime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(workflowSuspended); 5. Because we’re using an event handler named workflowSuspended,. .NET objects, workflow instances are executing within the confines of the workflow runtime. So events into and out of the workflow instance are brokered by the workflow runtime. The workflow runtime. sending data into an executing workflow, or from an executing workflow to the host application? Actually, you can do this with existing technology outside Windows Workflow Foundation (WF) using some