1. Trang chủ
  2. » Công Nghệ Thông Tin

microsoft press windows workflow foundation step by step phần 2 doc

47 362 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 47
Dung lượng 727,81 KB

Nội dung

23 Chapter 2 The Workflow Runtime After completing this chapter, you will be able to: ■ Be able to host the workflow runtime in your applications ■ Understand the basic capabilities of the WorkflowRuntime object ■ Know how to start and stop the workflow runtime ■ Be able to connect to the various workflow runtime events When you execute tasks in the Workflow Foundation (WF) environment, something needs to oversee that execution and keep things straight. In WF, that something is an object known as WorkflowRuntime. WorkflowRuntime starts individual workflow tasks. WorkflowRuntime fires events for different situations that pop up while your tasks execute. And WorkflowRuntime keeps track of and uses pluggable services you can hook in to the execution environment. (We’ll look at some of these pluggable services starting in Chapter 5, “Workflow Tracking.”) The overall WF architecture is shown in Figure 2-1. Figure 2-1 WF architecture Host Application Activity Activity Activity Activity Activity Threading Services Persistence Services Timer Services Custom Services Tracking Services External Data Services Transaction Services Managed Application Code Workflow Environment WorkflowRuntime WorkflowRuntime Workflow Instance AppDomain 24 Part I Introducing Windows Workflow Foundation (WF) WF and your application execute concurrently. In fact, WF requires your application as a host. The host application might be a Windows Forms application, a console application, an ASP.NET Web application, or even a Windows service. The WF runtime and your application execute together in a .NET AppDomain, and there can be only one instance of WorkflowRuntime per AppDomain. Attempting to create a second instance of WorkflowRuntime in a single AppDomain results in an InvalidOperationException. You build workflow applications—“workflows”—by creating logical groupings of activities. These logical groupings work to complete the workflow task you require. When you host the workflow runtime, you essentially hand the workflow your activities and tell it to execute them. This results in a workflow instance. The workflow instance is a currently executing workflow task, which is itself composed of logically grouped activities. And, as you recall from the first chapter, activities can execute code you provide as well as make decisions based on input data. We’ll cover workflow instances in the next chapter and activities in the chapters to follow. Hosting WF in Your Applications In the last chapter, we used the Microsoft Visual Studio workflow project template to build a basic workflow application for us. And in practice you would likely do just that. But if you’re like me, just executing wizards and such is fine only if you understand the code they’re insert- ing. After all, the code is yours to maintain and understand once the code generator’s job is complete. So what does it take to host WF in your application? Well, aside from building the workflow tasks that WF is to run (that’s your job), all you really need to do is reference the WF assem- blies and provide the necessary code to bring WorkflowRuntime into execution, start it, and manage the operational conditions you’re interested in managing. In that sense, hosting WF isn’t a lot different from using other .NET assemblies. The operational condition management amounts to handling events that the runtime will fire from time to time given specific condi- tions, such as when the runtime goes idle or an instance sustains an unhandled exception. There is quite a list of available events you can handle, and we’ll see some of those a bit later in the chapter, with still others introduced in Chapter 5, “Workflow Tracking,” and Chapter 6, “Loading and Unloading Instances.” Note WF can be hosted in a variety of applications, including Microsoft Windows Forms and Windows Presentation Foundation applications, console applications, ASP.NET Web applications, and Windows Services. The basic process remains the same as far as WF is concerned for all of these (very different) host application types. For now, though, let’s build a basic .NET console application and host the workflow runtime ourselves. This will help make the code the Visual Studio workflow project template inserts a little less mysterious. Chapter 2 The Workflow Runtime 25 Creating a basic console application 1. Start Visual Studio 2005 as you did in the previous chapter. 2. From the File menu, select New and then Project. 3. When the New Project dialog box appears, expand the Visual C# tree control node and then select Windows from the Project Types pane. 4. Select Console Application from the Templates pane. 5. In the Name field, type WorkflowHost. 6. In the Location field, type \Workflow\Chapter2. Note Remember that the path \Workflow represents the path you are using to store the book’s sample applications. 7. Click OK to create the WorkflowHost project. At this point, we have a basic console application, but of course it does nothing interesting. Now let’s begin adding workflow components. Speaking personally, I truly love the Visual Studio IntelliSense functionality. But for that to take effect, you have to first reference the assemblies IntelliSense will interpret to help you write code. So a great place to start is to reference the workflow assemblies before adding any code. This way, when we do add code, we can take advantage of the Visual Studio code assistance capabilities. Adding the workflow assembly references 1. In the Visual Studio Solution Explorer pane, right-click the References tree node and select Add Reference. Tip Selecting Add Reference from the Visual Studio Project menu achieves the same result. 26 Part I Introducing Windows Workflow Foundation (WF) 2. This activates the Add Reference dialog box. Using the vertical scrollbar’s thumb control, scroll down until you find System.Workflow.Runtime. Select that using a single mouse click. 3. Click OK to add the reference. Visual Studio has now added the workflow runtime reference you’ll need to execute workflow tasks. What we’ve not done is actually bring the workflow runtime into execution. To do that, we need to add some code to our application—here’s what we’ll do. Hosting the workflow runtime 1. If it’s not already open, open the Program.cs file for editing as you did in the previous chapter. 2. Locate the following code (which is located at the top of the source file): using System; using System.Collections.Generic; using System.Text; 3. Add the following line of code, just after the System.Text line: using System.Workflow.Runtime; 4. Locate the Main method, and add the following line of code after the opening curly brace: WorkflowRuntime workflowRuntime = new WorkflowRuntime(); 5. For now, we’ll just compile the program to make sure there are no errors. We’ll use this application throughout the chapter, so keep Visual Studio running, or reload this appli- cation as necessary while progressing through the chapter. To compile, select Build WorkflowHost from the Visual Studio Build menu. Chapter 2 The Workflow Runtime 27 A Closer Look at the WorkflowRuntime Object Now that we have an instance of WorkflowRuntime created in our WorkflowHost application, it’s time to take a brief look at how we interact with this object. Like most useful objects, WorkflowRuntime exposes a set of methods and properties we use to control the workflow runtime environment. Table 2-1 lists all the WorkflowRuntime properties, while Table 2-2 lists the methods we typically use. There are more methods associated with WorkflowRuntime, but the methods shown in Table 2-2 are the ones most commonly used and the ones we’ll focus on both here and in the remainder of the book. There are also a number of events WorkflowRuntime will raise at vari- ous times during workflow execution, but we’ll examine those a bit later in the chapter. Table 2-1 WorkflowRuntime Properties Property Purpose IsStarted Used to determine whether the workflow runtime has been started and is ready to accept workflow instances. IsStarted is false until the host calls Star tRuntime. It remains true until the host calls StopRuntime. Note you cannot add core services to the workflow runtime while it is running. (We’ll address starting services in Chapter 5.) Name Gets or sets the name associated with the WorkflowRuntime. You cannot set Name while the workflow runtime is running (that is, when IsS tarted is true). Any attempt to do so will result in an InvalidOperationException. Table 2-2 WorkflowRuntime Methods Method Purpose AddService Adds the specified service to the workflow runtime. There are lim- itations regarding what services can be added as well as when. We’ll look at services in more detail starting in Chapter 5. CreateWorkflow Creates a workflow instance, including any specified (but optional) parameters. If the workflow runtime has not been started, the CreateWorkflow method calls StartRuntime. GetWorkflow Retrieves the workflow instance that has the specified workflow instance identifier (which consists of a Guid). If the workflow instance was idled and persisted, it will be reloaded and executed. StartRuntime Starts the workflow runtime and the workflow runtime services and then raises the Started event. StopRuntime Stops the workflow runtime and the runtime services and then raises the Stopped event. 28 Part I Introducing Windows Workflow Foundation (WF) Basically, then, working with WorkflowRuntime involves calling a few simple methods and handling some events of interest. There is a significant limitation WorkflowRuntime imposes, however, which we’ll look at next. Building a Workflow Runtime Factory I mentioned this previously in the chapter, but it is important enough to mention again—there can be only a single instance of WorkflowRuntime per AppDomain. And because the majority of .NET applications use only a single AppDomain, it necessarily follows that you can gener- ally use only a single instance of WorkflowRuntime in your application. Whenever I hear “use only a single instance,” I naturally think of using a combination of the singleton and factory patterns. The singleton pattern, if you’re unfamiliar with patterns, is sim- ply a mechanism for assuring that no matter how many times your application requests instances of the singleton object, only one instance of the singleton is ever given out. This is typically done for objects that are considered “expensive” to create, such as objects that con- sume a large number of resources or take a significant amount of time to be created. The concept of a singleton, which is to say only a single object is ever created and handed to your application, dovetails nicely with the factory pattern. The factory pattern involves an intermediate object that’s used to create instances of other objects. Most of us, for example, don’t build our own cars. Instead, we purchase them from the automobile manufacturer, at least indirectly. (Many of us, I’m sure, wish we could buy them directly!) The combination of the singleton and factory is powerful because the factory can make sure only a single instance of the singleton object is ever created. This is perfect for our needs, because within our application it’s entirely possible that different pieces of the application might try to load and start the workflow runtime (independent application modules, for instance). Let’s see how we might create a WorkflowRuntime factory. Creating the WorkflowRuntime factory object 1. We’ll need to add a new class to our WorkflowHost poject. To do that, right-click on the project name (WorkflowHost) in the Visual Studio Solution Explorer and select Class from the Add menu item. Tip Selecting Add Class from the Visual Studio Project menu achieves the same result. Chapter 2 The Workflow Runtime 29 2. The Add New Item dialog box should now appear, and because we requested that a new class be created, the Class item in the Templates pane should already be selected. There- fore, we’ll only need to name the source file (which indirectly also names the object we’re creating). Type WorkflowFactory.cs into the Name field and click Add. 3. As we did with the main application source file, Program.cs, we’ll need to add the using directive for the workflow assembly to the top of the WorkflowFactory source file. The WorkflowFactory source file should be open for editing because we just created it, but if not, open it for editing using the techniques we used for opening Program.cs in the previous chapter. To add the using directive, locate this code at the top of the WorkflowFactory.cs file: using System; using System.Collections.Generic; using System.Text; 30 Part I Introducing Windows Workflow Foundation (WF) After the using directive for System.Text, add the following line: using System.Workflow.Runtime; 4. The using directive introduces the workflow runtime assembly to our source file, but it does little more. We need to add the code to represent the singleton object to the WorkflowFactory class. To do that, locate the WorkflowFactory class definition: class WorkflowFactory { } Not much of a class yet! But we’ll fix that. Just after the opening curly brace of the class definition, add these lines of code: // Singleton instance of the workflow runtime. private static WorkflowRuntime _workflowRuntime = null;| // Lock (sync) object. private static object _syncRoot = new object(); 5. Notice that the field _workflowRuntime is initialized to null. Our factory will sense this and create a new instance of WorkflowRuntime. If workflowRuntime is not null, our factory won’t create a new instance but will hand out the existing instance. To do this, we’ll need to add a method designed to create and return our singleton object. Moreover, we’ll make the method static so that objects requesting the workflow runtime object don’t need to create instances of the factory. To do this, we’ll add the following code just after the _syncRoot field: // Factory method. public static WorkflowRuntime GetWorkflowRuntime() { // Lock execution thread in case of multi-threaded // (concurrent) access. lock (_syncRoot) { // Check for startup condition. if (null == _workflowRuntime) { // Not started, so create instance. _workflowRuntime = new WorkflowRuntime(); } // if // Return singleton instance. return _workflowRuntime; } // lock } 6. Almost there! When the Visual Studio class template builds a new class, it omits the public keyword on the class definition, making it a private class. Because we want other classes to be able to request instances of WorkflowRuntime, we’ll need to make the factory class public. While we’re at it, we’ll also mark the class as static to prevent direct Chapter 2 The Workflow Runtime 31 instantiation (it’s a factory class, after all). To make all this happen, we’ll change the class definition from this class WorkflowFactory to this: public static class WorkflowFactory With WorkflowFactory in hand, any part of your application can request the workflow runtime without getting slammed with an InvalidOperationException. Later, starting in Chapter 5, we’ll make slight revisions to this class to account for other startup services we might want to include. Tip I like placing all the startup and shutdown code in this factory because it puts all the runtime initialization code in one place, making future changes and maintenance easier. No matter what object requests access to the workflow runtime, we know the runtime has been initialized according to our design. Starting the Workflow Runtime Of course, no sooner have you created your WorkflowFactory object than I’ll ask you to modify it. I’ve done this intentionally because I wanted to single out how the workflow runtime is started. Referring back to Table 2-2, we see that there is a method called StartRuntime, and making that method call from within our factory object makes a lot of sense. External objects requesting the workflow runtime object (presumably to create new workflow instances) do not need to deal with or worry about the initialization state of the runtime environment. We have a one-stop place to establish the environment as required by our application. The exter- nal objects requesting the workflow runtime object can simply use it without making further changes to the environment as they receive it. Calling StartRuntime is not absolutely required. If we were to create a workflow instance, StartRuntime would be called internally for us. And if all we ever did was create an instance of WorkflowRuntime, I probably wouldn’t worry about calling StartRuntime explicitly. Once we add services, however (starting in Chapter 5), I think the explicit call makes a lot of sense, if only for code-maintenance purposes and to ensure the runtime environment’s state is prop- erly established as the workflow runtime object is passed out to whoever asks for it. So let’s make the slight change to our factory object and call StartRuntime directly. Starting the workflow runtime 1. With Visual Studio running and WorkflowFactory.cs open for editing, locate this line of code: _workflowRuntime = new WorkflowRuntime(); 32 Part I Introducing Windows Workflow Foundation (WF) 2. Following this line of code, add this new line: // Start the runtime. _workflowRuntime.StartRuntime(); Stopping the Workflow Runtime If there is a way to start the workflow runtime, it makes sense that there is a way to stop it as well. And in fact there is. Looking back at Table 2-2, we see there is a StopRuntime method that matches, and countermands, StartRuntime. Calling StopRuntime unloads all executing work- flows and services and shuts down the runtime environment. Of course, the appropriate place to call StopRuntime is just prior to or during your application shutdown logic, or as the AppDomain is being torn down. Tip Just as calling StartRuntime is not mandatory (but not a bad idea), calling StopRuntime also isn’t mandatory (but is similarly a good idea). As the WF runtime assembly unloads, StopRuntime is called automatically. Note You cannot call StopRuntime once the WorkflowRuntime object is marked as disposed. Doing so results in an ObjectDisposedException. Depending on the timing of your application termination, this might be something to watch out for. A great place to provide for this is in the WorkflowFactory object. Let’s modify WorkflowFactory to automatically shut the workflow runtime down for us. Stopping the workflow runtime 1. With Visual Studio running and WorkflowFactory.cs open for editing, locate this line of code: _workflowRuntime = new WorkflowRuntime(); 2. Prior to this line of code, add these lines of code: // Provide for shutdown AppDomain.CurrentDomain.ProcessExit += new EventHandler(StopWorkflowRuntime); AppDomain.CurrentDomain.DomainUnload += new EventHandler(StopWorkflowRuntime); 3. Then add the StopWorkflowRuntime to the WorkflowFactory class: // Shutdown method static void StopWorkflowRuntime(object sender, EventArgs e) { if (_workflowRuntime != null) { [...]... System .Workflow. Runtime; System.Threading; namespace WorkflowHost { class Program { private static AutoResetEvent waitHandle = new AutoResetEvent(false); static void Main(string[] args) { WorkflowRuntime workflowRuntime = WorkflowFactory.GetWorkflowRuntime(); workflowRuntime.WorkflowIdled += new EventHandler(workflowIdled); workflowRuntime.WorkflowCompleted += new EventHandler... Workflow Tracking.” Table 3-1 WorkflowInstance Properties Property Purpose InstanceId Gets the unique identifier for the workflow instance (a Guid) WorkflowRuntime Gets the WorkflowRuntime for this workflow instance Table 3 -2 WorkflowInstance Methods Method Purpose ApplyWorkflowChanges Applies changes to the workflow instance specified by the WorkflowChanges object This allows you to modify the workflow. .. handler for workflow completion: workflowRuntime.WorkflowCompleted += new EventHandler(workflowCompleted); 4 And now add the handler for the WorkflowTerminated event: workflowRuntime.WorkflowTerminated += new EventHandler(workflowTerminated); 5 If you compile and run WorkflowHost, the application should compile and execute But there is no workflow. .. hook up the three event handlers (idle, completed, and terminated) workflowRuntime.WorkflowIdled += new EventHandler(workflowIdled); workflowRuntime.WorkflowCompleted += new EventHandler(workflowCompleted); workflowRuntime.WorkflowTerminated += new EventHandler(workflowTerminated); 3 Now we’ll add some logic to test the incoming... this line of code a bit further down: WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(LongRunningWorkflow .Workflow1 )); 5 Change this line of code to match the following: WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(LongRunningWorkflow .Workflow1 ), parms); With that last step, we’re done adding code Compile the application by selecting Build Solution from the Visual... it Using the workflow runtime factory object 1 With Visual Studio running and Program.cs open for editing, locate this line of code: WorkflowRuntime workflowRuntime = new WorkflowRuntime(); 2 Replace this line of code with the following: WorkflowRuntime workflowRuntime = WorkflowFactory.GetWorkflowRuntime(); Subscribing to Workflow Runtime Events It might seem like there isn’t a lot to WorkflowRuntime,... Synchronously suspends the workflow instance If the workflow instance is already suspended, nothing happens If the instance is running, the workflow runtime suspends the workflow instance, sets SuspendOrTerminateInfoProperty to the string (reason) passed into Suspend, and raises the WorkflowSuspended event 42 Part I Introducing Windows Workflow Foundation (WF) Table 3 -2 WorkflowInstance Methods Method... waitHandle.Set(); } static void workflowCompleted(object sender, 37 38 Part I Introducing Windows Workflow Foundation (WF) WorkflowCompletedEventArgs e) { Console.WriteLine( "Workflow instance completed."); waitHandle.Set(); } static void workflowIdled(object sender, WorkflowEventArgs e) { Console.WriteLine( "Workflow instance idled."); } } } What are we missing? A workflow to execute! We’ll dive into workflow instances... can tailor those to suit your purpose using the Microsoft Visual Studio Properties pane 39 40 Part I Introducing Windows Workflow Foundation (WF) We used the workflow designer briefly in Chapter 1, “Introducing Microsoft Windows Workflow Foundation, ” and we’ll use it again here After all, working with WF is all about building workflow tasks, and the workflow visual designer is a huge part of that development... code in the Main method: Console.WriteLine("Waiting for workflow completion."); 5 After this line of code, add the following: WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(LongRunningWorkflow .Workflow1 )); instance.Start(); 6 Compile and execute the WorkflowHost application Tip If you execute the WorkflowHost application by pressing F5 in Visual Studio, the application will complete . WorkflowRuntime workflowRuntime = WorkflowFactory.GetWorkflowRuntime(); workflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(workflowIdled); workflowRuntime.WorkflowCompleted. Studio running and WorkflowFactory.cs open for editing, locate this line of code: _workflowRuntime = new WorkflowRuntime(); 32 Part I Introducing Windows Workflow Foundation (WF) 2. Following this. Services Managed Application Code Workflow Environment WorkflowRuntime WorkflowRuntime Workflow Instance AppDomain 24 Part I Introducing Windows Workflow Foundation (WF) WF and your application

Ngày đăng: 06/08/2014, 02:20

TỪ KHÓA LIÊN QUAN