CHAPTER 7 ■ AZURE .NET SERVICES—WORKFLOWS 213 Listing 7-1. ShoppingCart WCF Service Library using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.ServiceModel; namespace CloudWorkflowServiceLibrary { [ServiceContract] public interface IShoppingCartService { [OperationContract(IsOneWay = true)] void Ping(); } [DataContract] public class ShoppingCartItem { [DataMember] public string SKU; [DataMember] public string ProductName; [DataMember] public DateTime AddTime; [DataMember] public int ItemCount; } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.ServiceModel; using System.Diagnostics; namespace CloudWorkflowServiceLibrary { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class ShoppingCartService : IShoppingCartService { public void Ping() { string message = CHAPTER 7 ■ AZURE .NET SERVICES—WORKFLOWS 214 string.Format(" {0}:Ping, {1}", DateTime.Now.ToString(), this.ToString()); Trace.WriteLine(message); Console.WriteLine(message); } #endregion } } 2. Create a console application project to host the WCF service that we have just created. Name the project ShoppingCartServiceHost. Add a reference to System.ServiceModel.dll and Microsoft.ServiceBus.dll. (This assembly can be found in C:\Program Files\Microsoft .NET Services SDK\Assemblies.) Insert a few lines of code into the Main() method body as Listing 7-2 shows. The setting options NetEventRelayBinding, TransportClientEndpointBehavior, and UserNamePassword credentials to authenticate to the .NET Service Bus are needed here because the workflow will be calling the service. There is not much difference from the Main() methods we have seen in previous chapters: the security authentication type can be switched from the user name and password to other types such as CardSpace or X.509 certificate. Listing 7-2. Local WCF Service Host ShoppingCartServiceHost using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; namespace ShoppingCartServiceHost { using Microsoft.ServiceBus; using CloudWorkflowServiceLibrary; class Program { static void Main(string[] args) { ServiceHost host = new ServiceHost(typeof(ShoppingCartService)); ServiceEndpoint endpoint = host.AddServiceEndpoint("CloudWorkflowServiceLibrary.IShoppingCartService", new NetEventRelayBinding(), "sb://servicebus.windows.net/services/SoftnetSolutions 113/ShoppingCart"); TransportClientEndpointBehavior transportEndpointBehavior = new TransportClientEndpointBehavior(); transportEndpointBehavior.CredentialType = TransportClientCredentialType.UserNamePassword; transportEndpointBehavior.Credentials.UserName.UserName = "[your user name]"; CHAPTER 7 ■ AZURE .NET SERVICES—WORKFLOWS 215 transportEndpointBehavior.Credentials.UserName.Password = "[your solution password]"; endpoint.Behaviors.Add(transportEndpointBehavior); try { host.Open(); Console.WriteLine("Host is running"); Console.ReadLine(); host.Close(); } catch (Exception ex) { Console.WriteLine( string.Format(" ShoppingCartServiceHost:Main, exception caught {0}", ex.Message)); } } } } 3. Create a cloud sequential workflow project from Visual Studio as shown in Figure 7-2 and call it CloudSequentialShoppingCartWorkflow. Figure 7-2. Create a cloud sequential workflow project CHAPTER 7 ■ AZURE .NET SERVICES—WORKFLOWS 216 4. Drag a CloudXPathUpdate from the toolbox and drop it on the workflow design surface, as Figure 7-3 shows. Call it CreateShoppingCartServiceBusMessage. Figure 7-3. Add a CloudXPathUpdate activity to the design surface 5. Enter the binding information into the Properties dialog box as shown following. At runtime, the input information (InNewValue) will be populated into the <input></input> node using the XPath expression as the search string. InNewValue = "Hello from ShoppingCart Workflow" InXml = "<Ping><input></input></Ping>" InXPathExpresssion ="/Ping/input" 6. Add a CloudServiceBusSend activity below the CloudXPathUpdate activity on the workflow design surface and call it SendShoppingCartInfo. 7. Make sure the binding information is as following. Action = "urn:IShoppingCartService/Ping" Body Name = "CreateShoppingCartServiceBusMessage" Body Path = "OutXml" ConnectionMode = "Multicast" URL = "sb://servicebus.windows.net/services/SoftnetSolutions 113/ShoppingCart" 8. Now we have all the necessary information for the workflow design and are ready to deploy to the Microsoft data center. Right-click on the workflow design surface to bring up the Workflow Cloud Deployment dialog box, and enter your credential information. 9. Go to https://workflow.ex.azure.microsoft.com/WorkflowManagement.asp and verify that the workflow has been successfully deployed to Microsoft as shown in Figure 7-4. CHAPTER 7 ■ AZURE .NET SERVICES—WORKFLOWS 217 Figure 7-4. Verifying that the service has been deployed using Azure Portal Before we finish our development let’s shift the topic a little bit to discuss the limitations of using cloud state machine workflows with the current .NET Workflow Service. In order to understand what is going to happen at runtime if we deploy a state machine workflow to the cloud, let us deploy a workflow with state machine type or with a custom-defined activity to the cloud. For example, let's switch back to our project and define a custom workflow activity as Listing 7-3 and Listing 7-4 show. This is a very simple custom activity used to send an e-mail notification when a WCF service call is received. If we host this workflow activity in a worker role like in Listing 7-2, we get a security exception, saying that the worker role failed to start because an assembly call cannot be loaded from a partially trusted assembly, as Figure 7-5 shows. Actually, the assembly related to the exception is System.Workflow.Activities as highlighted in Listing 7-3; we have to reference this assembly from the project, but it has not been . host.AddServiceEndpoint("CloudWorkflowServiceLibrary.IShoppingCartService", new NetEventRelayBinding(), "sb://servicebus .windows. net/services/SoftnetSolutions 113/ShoppingCart"); TransportClientEndpointBehavior. Path = "OutXml" ConnectionMode = "Multicast" URL = "sb://servicebus .windows. net/services/SoftnetSolutions 113/ShoppingCart" 8. Now we have all the necessary information