Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 133 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
133
Dung lượng
3,85 MB
Nội dung
888 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN ➤ Activities that communicate with external code — These activities are either called by external code to initiate a workflow or used to call to external code as part of a workflow. This category also includes activities that communicate with external systems to persist the workflow state. ACTIVITY DESCRIPTION Receive Receives a one-way WCF message ReceiveAndSendReply Receives a WCF message and sends back a result Send Sends a one-way WCF message SendAndReceiveReply Sends a WCF message and waits for a result Persist Saves the current state of the workflow. This is very useful for long-running workflows, as it enables you to save the current state of the workflow, saving memory. You can then reload the workflow as it was persisted as needed later. ACTIVITY DESCRIPTION CancellationScope Marks the boundaries of a set of activities to perform if a process is cancelled. Typically, this would be used to close any handles, undo any partially completed steps, etc. CompensableActivity Marks the boundaries of an activity that may be “undone.” This activity groups one or more actions to be performed. In addition, it contains actions to undo whatever steps may have already been performed. This is typically to enable rollback of a partially failed transaction. This activity is used as an alternative to transactions when you don’t necessarily control the success of each of the steps in a process. For example, if you send a request to a Web service, and then fail another step, the CompensableActivity can send a cancel request to the Web service. Compensate Invokes the compensation activity in a CompensableActivity activity. That is, it “undoes” whatever activity was performed. Confirm Performs the equivalent of a commit on the CompensableActivity TransactionScope Marks the boundaries of a transaction within the workflow Rethrow Rethrows an existing exception. This is typically done within the Catch clause of a Try Catch activity to propagate the exception to another part of the workflow. Throw Creates an exception within a workflow TryCatch Wraps an activity (use a sequence if you need multiple children) within a Try Catch block to handle exceptions CorrelationScope Marks the boundaries of a set of Web services that will share a correlation handle InitializeCorrelation Allows you to initialize a correlation. Typically, this is done using a message, but this activity allows you to start it without an explicit correlation message. TransactedReceiveScope Allows you to flow a transaction into a WCF communication ➤ Transaction activities — These activities group a number of other activities together into some logical element. This is usually done to mark a number of activities that participate in a transaction. ACTIVITY DESCRIPTION Switch<T> Works like the VB case statement. Switches the flow through a workflow based on the value of a variable or condition. While Works like the VB while…end while loop. Performs a child activity (use a sequence if you need multiple steps) while a condition is true. TerminateWorkflow Stops the workflow before the end of the workflow is reached. This is useful in the event of errors in the workflow, or if the data input doesn’t allow for completion. Also used for flowchart workflows as a means of completion. (continued) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ➤ Flowchart activities — These activities are used in flowchart-style workflows and allow for the organization of the steps, simple decisions, and other stages. ACTIVITY DESCRIPTION Flowchart This activity is used to create a flowchart workflow. It is a container for all the steps involved in the workflow. FlowDecision A simple If statement within a flowchart workflow. This is used to control the actions of a workflow based on a condition. FlowSwitch A switch statement within a flowchart workflow. This works similar to the VB case statement in that you have multiple cases that work based on the assigned condition. You also define a default condition if none of the cases apply. A Less Simple Workflow To see a few of these activities together, create a new Workflow Console Application named Fulfillment. This will be used to create part of a workflow for an order fulfillment application. The workflow will collect an XML file from a directory on disk, validate it using a few simple rules, and add it to a collection representing the order queue. Other workflows might then retrieve items from this collection for actual processing. Figure 26-13 shows the final workflow. As you can see from the figure, the workflow is a flowchart consisting of four stages. The DisplayName property of each of these stages has been set to better describe the contents of the stage. As you would expect, this is invaluable in improving the understanding of the workflow when you come back to it later (or try to explain it to end users). The basic outline of the workflow is as follows: The workflow begins a loop to monitor ➤ a directory for XML files. This file will represent an order, with one or more details. This is a DoWhile activity. Once an order is received, a few simple validations are performed by calling a method on a .NET ➤ class. This is an InvokeMethod activity. If the order is valid, it is added to a collection for later processing. If not, the validation errors are ➤ displayed and the workflow completes. This is an If activity. To demonstrate additional processing, the orders collection is simply displayed to the console. Of ➤ course, in a real application, this stage would send the orders on to another application for actual fulfillment and shipping. This is a ForEach<T> activity. Before you begin building the workflow, there are some helper classes that you need to build. These represent an order, an order detail line, and a manager class for processing the order. Add a new Class Library project to the solution, named OrderManager. This has three classes: Order, OrderDetail, and OrderSystem. The Order class represents an order in the system. For this example, it consists of a few properties, including the collection of order details.: Public Class Order Public Property OrderID As Integer Public Property OrderDate As Date Public Property CustomerName As String Public Property ShipAddress As String FIGURE 2613 Building Workflows ❘ 889 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 890 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN Public Property Details As List(Of OrderDetail) Public Sub New() Details = New List(Of OrderDetail) End Sub End Class Code snippet from OrderManager The OrderDetail class is an individual line item within an order. Again, for this example it is greatly simplified: Public Class OrderDetail Public Property Parent As Order Public Property ItemName As String Public Property Quantity As Integer End Class Code snippet from OrderManager The OrderSystem class is a general manager class for the orders. In addition to the functionality for this demo, it would likely be responsible for saving orders to a database, and so on: Public Class OrderSystem Public Function GetOrderFromDropFile(ByVal path As String) As Order Dim result As Order = Nothing Dim files As String() Dim doc As New XDocument Dim detail As OrderDetail files = IO.Directory.GetFiles(path) If files.Length > 0 Then doc = XDocument.Load(files(0)) 'load header result = New Order With result .OrderID = CInt(doc.Root.Attribute("id").Value) .CustomerName = doc.Root.Element("customerName").Value .OrderDate = CDate(doc.Root.Element("orderDate").Value) .ShipAddress = doc.Root.Element("shipAddress").Value End With 'load detail rows Dim details As List(Of XElement) = (From item In doc.Descendants Where item.Name = "orderDetail" Select item).ToList For Each d In details detail = New OrderDetail With detail .Parent = result .ItemName = d.Element("itemName").Value .Quantity = CDec(d.Element("quantity").Value) End With result.Details.Add(detail) Next 'delete file to avoid calling this again 'likely you would move to a backup directory instead ' IO.File.Delete(files(0)) End If Return result Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com End Function Public Function ValidateOrder(ByVal anOrder As Order) As String() Dim result As New List(Of String) 'check for OrderID If Not IsNumeric(anOrder.OrderID) Then result.Add("Order ID is not valid") End If 'check for ship address If Not String.IsNullOrEmpty(anOrder.ShipAddress) Then result.Add("No ship address") End If 'check for at least one OrderDetail If anOrder.Details.Count < 1 Then result.Add("Must have at least one item in order") End If 'other checks here Return result.ToArray End Function End Class Code snippet from OrderManager For this example, the OrderSystem class exposes two methods. The first attempts to load an XML file from an assigned directory. Once a file has been loaded, it converts the contents of the XML file into an Order object, and one or more OrderDetail objects. LINQ to XML is used to retrieve the rows containing order details. The second method does a few simple validations on the order, and returns a list of validation errors (as strings) to the calling program. The following code shows a sample order XML file (also included in the source code for the OrderManager project): <?xml version=”1.0” encoding=”utf-8” ?> <order id=”1234”> <orderDate>2009-12-01</orderDate> <customerName>Moe’s Family Diner</customerName> <shipAddress>1313 Mockingbird Lane, Springfield, AK</shipAddress> <orderDetails> <orderDetail> <itemName>Mango puree</itemName> <quantity>2</quantity> </orderDetail> <orderDetail> <itemName>Everso Sharp Knives</itemName> <quantity>15</quantity> </orderDetail> <orderDetail> <itemName>Mega frier</itemName> <quantity>1</quantity> </orderDetail> <orderDetail> <itemName>Case of sparklers</itemName> <quantity>200</quantity> </orderDetail> </orderDetails> </order> Code snippet from OrderManager Building Workflows ❘ 891 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 892 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN Build the project to ensure you have no errors, and then you’re ready to build the workflow to use these classes. Add a new Flowchart activity to the designer, and add the four activities shown in Figure 26-12, connecting them as shown. The workflow will make use of the objects in the OrderManager project. As such, you should import that namespace into your workflow. First, add a reference to the OrderManager project: Right click on the Fulfillment project and select Add Reference. Select the OrderManager project on the Projects tab. Next, click the Imports link at the bottom of the workflow designer on the FulfillmentWorkflow. This displays the current list of namespaces available to your workflow. Add the OrderManager namespace by entering it in the space at the top of the list and pressing Enter to save it to the list. The DoWhile loop consists of a Sequence, which in turn contains a Delay activity and an InvokeMethod activity (see Figure 26-14). The DoWhile activity requires that you set a condition that will end the loop. In this case, it will be when an order has been picked up by the InvokeMethod. The following table describes the property settings for the added activities. FIGURE 2614 ACTIVITY PROPERTY VALUE DESCRIPTION DoWhile Condition theOrder Is Nothing You will create the theOrder variable shortly. This variable will hold an instance of an Order class for processing. Delay Duration 00:00:10 The Duration property is a TimeSpan. In this case, the delay is set for 10 seconds. In a real-world application, you would set this based on the frequency of orders being processed. InvokeMethod TargetObject manager This is an instance of an OrderSystem class. MethodName GetOrderFromDropFile A method on the OrderSystem class Result theOrder Once a new file has been processed, the resulting order is saved for processing within the workflow. Parameters System .Configuration .ConfigurationManager .AppSettings(“dropFilePath”) .ToString() The directory to monitor will be set using the application configuration file. The InvokeMethod activity is used to call the ValidateOrder method on the manager object. Set the properties on this activity as shown in this table: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com FIGURE 2615 ACTIVITY PROPERTY VALUE DESCRIPTION InvokeMethod TargetObject manager This is an instance of an OrderSystem class. MethodName ValidateOrder A method on the OrderSystem class Result ValidationErrors A variable that will be added to the workflow shortly Parameters theOrder The instance of the Order class created by the GetOrderFromDropFile method above Building Workflows ❘ 893 ACTIVITY PROPERTY VALUE DESCRIPTION If Condition ValidationErrors .Length > 0 The condition will return true if any errors were added to the collection by the earlier ValidateOrder call. AddToCollection<T> TypeArgument OrderManager .Order This defines the type of objects stored in the collection. Collection Orders This is a variable of the workflow that will store the orders. Item theOrder The item to add to the collection. In this case it is a workflow variable. ForEach<T> TypeArgument String This will iterate over each of the items in the ValidationErrors collection to display them. Values ValidationErrors This is the collection to iterate over. WriteLine Text ValidationError This is the value of the current iteration in the loop. TerminateWorkflow Reason “One or more orders have errors” This will be available to the calling application to determine why the workflow terminated. Next, the processing branches based on whether errors are encountered in the order. If the order is valid, then it is added to a collection for further processing. If, however, there are any validation errors, they are displayed and the workflow ends (see Figure 26-15). Set the properties for these activities as follows: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 894 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN Finally, the orders are simply displayed on the console to confirm they have been processed. This is done with another ForEach<T> activity that writes the order’s information, followed by each of the detail rows in the order (see Figure 26-16). The properties of these activities are defined as follows: ACTIVITY PROPERTY VALUE DESCRIPTION ForEach<T> TypeArgument OrderManager.Order This will iterate over each of the orders in the collection to display them. Values Orders This is a workflow variable containing the orders submitted. WriteLine Text String .Format(“Order on {0} by {1} for:”, item .OrderDate, item .CustomerName) Displays the contents of the order’s header information ForEach<T> TypeArgument OrderManager .OrderDetails This will iterate over the detail rows contained within the submitted order. Values item.Details This is the collection of order details within the current order. WriteLine Text String .Format(“{0} {1}(s)”, detail .Quantity, detail .ItemName) Displays the contents of the fields of each order detail row FIGURE 2616 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com VARIABLE TYPE DESCRIPTION theOrder OrderManager.Order Will hold the current submitted order Orders List<Order> Represents the current queue of orders for processing. Set the default to New List(Of Order) to ensure that the collection is initialized. ValidationErrors String() Will hold any validation errors in the current submitted order ARGUMENT TYPE DESCRIPTION manager OrderManager.OrderSystem Will hold the object that provides the processing for the loading and validating of the orders As described above, you will use a number of workflow variables needed to store data during processing. These are described in the following table: All that remains is to update the host application. As described above, you will provide an instance of the OrderSystem class to the workflow. This is done in the Main method for the Console application: Shared Sub Main() Dim inputs As New Dictionary(Of String, Object) 'Workflow expects the OrderSystem as parameter Dim sys As New OrderManager.OrderSystem inputs.Add("manager", sys) WorkflowInvoker.Invoke(New FulfilmentWorkflow(), inputs) Console.WriteLine("Press ENTER to exit") Console.ReadLine() End Sub Code snippet from Fulfillment Recall that the input for a workflow is a Dictionary(Of String, Object), and that the key in this dictionary must match the name of an argument in the system — in this case, manager. Before running the application, you also need to add an application configuration file. This will include a single application setting named dropFilePath that should be set to the location where you will add the XML files. Run the application and copy an XML file to the monitored directory. After a brief delay, you should see the contents of the order displayed on the console (see Figure 26-17). FIGURE 2617 Building Workflows ❘ 895 In addition to those variables, an instance of the OrderSystem class will be passed into the workflow as an argument. Open the Arguments pane and add the following item. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 896 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN Building Custom Activities In addition to the standard activity library, WF supports extensibility through the creation of custom activities. Creating custom activities is a matter of creating a new class that inherits from Activity (or one of the existing child classes). Creating custom activities is the primary means of extending WF. You might use custom activities to simplify a complex workflow, grouping a number of common activities into a single new activity. Alternatively, custom activities can create a workflow that is easier to understand, using terms that are more familiar to the developers and business experts. Finally, custom activities can be used to support software used within the business, such as activities to communicate with a Customer Relationship Management (CRM) or Enterprise Resource Planning (ERP) system. Creating custom activities with WF 4 is much easier than it was with earlier releases. To create a custom activity, you inherit from Activity, or one of the existing children of Activity, and override the appropriate methods. The most common classes you will inherit from are as follows: ➤ Activity — The base class. Use only if one of the other following three classes are too specific for your needs. ➤ CodeActivity — Use when your activity performs some action. You override the Execute method to carry out your action. This activity works synchronously (as opposed to the AsyncCodeActivity below), so the entire activity must complete before the workflow continues. ➤ AsyncCodeActivity — Similar to CodeActivity, but the work is performed asynchronously. This is the most commonly used class to inherit from when creating custom activities. ➤ NativeActivity — Use this when your activity needs to interact with the workflow engine itself. For example, the flow control activities inherit from this class. When defining properties for your custom activities, you do not use the standard types. Instead, you use a generic class to wrap the type. This enables your properties to communicate with the running workflow. There are three wrappers you should use in your activities: ➤ InArgument(Of type) — Used to wrap a property that will be provided to the workflow ➤ OutArgument(Of type) — Used to wrap a property that the workflow will expose to the calling code ➤ InOutArgument(Of type) — Used to wrap a property that will be provided to the workflow, as well as returned To see how you can easily create a new activity and use it within a workflow, create a new Workflow Console application (CustomActivity). Add a new class (EncryptActivity) to the project for your new activity. This new activity will be used to encrypt a string within a workflow (you’ll also be creating an activity to decrypt the text): Imports System.Activities Imports System.Security.Cryptography Imports System.Text Public Class EncryptActivity Inherits CodeActivity Public Property Input As InArgument(Of String) Public Property Password As InArgument(Of String) Public Property Output As OutArgument(Of String) Protected Overrides Sub Execute(ByVal context As CodeActivityContext) Dim aes As New AesCryptoServiceProvider Dim hash As New MD5CryptoServiceProvider 'load the properties from the current workflow context Dim plaintext As String = Input.Get(context) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Dim pwd As String = Password.Get(context) Dim inBuffer As Byte() Dim outBuffer As Byte() 'the key is the input to the encryptor 'we can only decrypt using the same password aes.Key = hash.ComputeHash(Encoding.ASCII.GetBytes(pwd)) 'Electronic CodeBook format (each block is encrypted individually) aes.Mode = CipherMode.ECB Dim encrypt As ICryptoTransform = aes.CreateEncryptor inBuffer = Encoding.ASCII.GetBytes(plaintext) 'here's the actual encryption outBuffer = encrypt.TransformFinalBlock(inBuffer, 0, inBuffer.Length) 'store the output in the current workflow context 'Base64 to avoid any high ASCII issues Output.Set(context, Convert.ToBase64String(outBuffer)) End Sub End Class Code snippet from CustomActivity The encryption uses the AES encryption, although you could use any of the encryption methods in the System.Security.Cryptography namespace. You can see Chapter 34 for more details on the classes in this namespace, but the mechanics of using them are as follows: 1. Create an instance of one of the cryptography service providers. 2. Set the Key (and optionally IV, or initialization vector, properties) on the service provider. This is the value used to provide the encryption (i.e., the password). 3. Create an actual encryptor using the service provider. 4. Encrypt the text. Note that the encryption method (TransformFinalBlock) does not take a string, but an array of bytes, so you need to convert your input (and output). Add another class (DecryptActivity) to the project. The code for the DecryptActivity is basically a mirror image of the EncryptActivity: Imports System.Activities Imports System.Security.Cryptography Imports System.Text Public Class DecryptActivity Inherits CodeActivity Public Property Input As InArgument(Of String) Public Property Password As InArgument(Of String) Public Property Output As OutArgument(Of String) Protected Overrides Sub Execute(ByVal context As CodeActivityContext) Dim aes As New AesCryptoServiceProvider Dim hash As New MD5CryptoServiceProvider 'convert the input parameters from the current context Dim encryptedtext As String = Input.Get(context) Dim pwd As String = Password.Get(context) Dim inBuffer As Byte() Building Workflows ❘ 897 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... close the ProVB2010_Localization application you started with and create a new ASP.NET website called ProVB_Russian Alternatively, you can open this download folder as a website in Visual Studio 2010 On the default.aspx page add a new Calendar control from the toolbox, following the text: Welcome to ASP.NET! Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Cultures and Regions ... an example: 08/ 11/20 08 Is this date August 11, 20 08 or is it November 8, 20 08? It should be the job of the business logic layer or the presentation layer to convert all date and times for use by the end user To avoid interpretation errors, always use the same culture (or invariant culture) when storing values, such as dates and times, in a database or other data store Simpo PDF Merge and Split Unregistered... project called ProVB2010_Localization, and add the appropriate button and text box controls A copy of the code in this chapter is part of the code download with the name ProVB2010_Localization Add a new Sub DisplayCultureInfo and have it called by the Click event handler for the test button on the form When the TestButton_Click event is fired, the user’s culture information is retrieved and displayed in... of cultures, each of which has a language and a set of defined ways in which it views and consumes numbers, uses currencies, sorts alphabetically, and so on The NET Framework defines languages and regions using the Request for Comments 1766 standard definition (tags for identification of languages — www.ietf.org/rfc/rfc1766.txt), which specifies a language and region using two-letter codes separated... WorkflowDesigner.Save and WorkflowDesigner.Load methods would likely come in handy) Figure 26-22 Summary While Windows Workflow Foundation does not have the visual glitz of WPF or the broad reach of WCF, it is a highly useful addition to the NET Framework Most business applications have some need for workflows, and having a standard means of creating a workflow ensures that the workflow is fully featured and accurately... PDF Merge and Split Unregistered Version - http://www.simpopdf.com Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 27 localization WhaT you Will learn in This chaPTer ➤ Understanding culture types ➤ Getting culture settings from a thread ➤ Declaring culture in ASP NET ➤ Understanding differences in dates ➤ Understanding differences in currency & numbers ➤ Understanding differences... controls, and even Visual Studio itself equip you to do the extra work required to bring your application to an international audience This chapter looks at some of the important items to consider when building your applications for the world culTures and regions As an example, the ASP.NET page that is pulled up in an end user’s browser runs under a specific culture and region setting When building an ASP.NET... different number symbols) and more to do with how the number separators are used for decimals or for showing amounts such as thousands, millions, and more For instance, in the English culture of the United States (en-US), numbers are represented in the following fashion: 5,123 ,45 6.00 From this example, you can see that the en-US culture uses a comma as a separator for thousands and a period for signifying... thousand separators and a comma for the decimal separator, whereas the French-speaking Swiss use an apostrophe for separating thousands, and a period for the decimal separator This demonstrates that not only do you need to consider dates and language constructs, but that it is also Figure 27-7 important to “translate” numbers to the proper format so that users of your application can properly understand... difference between the letter V and the letter W Therefore, if you are sorting using the Finnish culture setting, Vi comes after Wa, and thus, Vienna appears last in the list of strings in the sorting operation ASP.NET Resource Files When you work with ASP.NET, resources are handled by resource files A resource file is an XML-based file that has a resx extension You can have Visual Studio help you construct . in which it views and consumes numbers, uses currencies, sorts alphabetically, and so on. The .NET Framework defines languages and regions using the Request for Comments 1766 standard definition. ShipAddress As String FIGURE 2613 Building Workflows ❘ 88 9 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 89 0 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN Public Property. Workflows ❘ 89 1 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 89 2 ❘ CHAPTER 26 wiNdows woRkFlow FouNdatioN Build the project to ensure you have no errors, and then you’re