Share via


Getting Started

To run this sample, you must install the HPC Pack 2008 R2 Client Utilities Redistributable Package with Service Pack 1 (or higher) and the HPC Pack 2008 R2 SDK with Service Pack 1 (or higher). In addition, you need to have administrative access to your HPC cluster’s head node and WCF broker node.

To run the WCF service in Windows Azure nodes, you must have a valid Windows Azure account, a Windows Azure worker node template defined in your head node, and several Windows Azure worker nodes in the HPC cluster that are started and online. See the Deploying Azure Worker Nodes in Windows HPC Server 2008 R2 SP1 Step-by-Step Guide on TechNet for further information.

Note:
 Although this solution is for Visual Studio 2010, the SquareService project uses .NET Framework 3.5; this is because currently the HPC cluster cannot host WCF services compiled for .NET Framework 4.

Task 1 – Inspecting the WCF Service Project

In this task, you will inspect the WCF service project to see the contract and implementation of the service.

  1. Open Microsoft Visual Studio 2010 from Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010.
  2. Open the SquareService.sln solution file located in the SquareService\Source folder.
  3. In the Solution Explorer window, expand the SquareService project node, as shown in Figure 1:

    Figure 1

    The SquareService project

  4. Open the ISquareService.cs file and inspect the service contract. The service contract contains only one method: the Square method.
  5. Open the SquareService.cs file and inspect the contents of the service. The service implementation is a basic square calculation.
    1. Note the Console.WriteLine method call. This call will output a message, which you will be able to see in the task results window in the HPC 2008 R2 Cluster Manager application.
    2. Also note the ServiceContext.Logger.TraceEvent method calls. These method calls write debug information to a local trace file, which are collected after the job finishes running.

Task 2 – Inspecting the WCF Service Configuration

In this task, you will inspect the contents of the service’s configuration file. The service configuration file allows you to set how the HPC service host locates your service and hosts it. The configuration file also includes information on how to expose the service through the WCF broker node.

  1. In the SquareService project, open the SquareService.config file. Look for the <microsoft.Hpc.Session.ServiceRegistration>XML element:

    SquareService.config

    <microsoft.Hpc.Session.ServiceRegistration> <service assembly="\\MyHeadNode\Apps\SquareService\SquareService.dll" contract="SquareServiceContracts.ISquareService" type="Services.SquareService" includeExceptionDetailInFaults="true" maxConcurrentCalls="0" serviceInitializationTimeout="60000" stdError="" maxMessageSize="65536"> </service> </microsoft.Hpc.Session.ServiceRegistration>

  2. The following attributes are required to configure how the service is hosted:
    1. assembly. Defines the location of the service’s assembly file, which should contain both the service contract and the service implementation. Change the name of the head node machine to match yours.
    2. contract. Defines the fully qualified name of the service contract.
    3. type. Defines the fully qualified name of the service’s implementation class.
  3. Inside the SquareService.config file, locate the <brokerServiceAddresses> XML element under the <microsoft.Hpc.Broker>\<services> element. Each of the <add> XML elements defines a base address that the WCF broker node uses to listen for client service requests.
  4. Inside the SquareService.config file, locate the <system.serviceModel> XML element and inspect the contents of that element. This XML element contains the configuration for the broker service’s message logging as well as the binding configuration for the endpoints exposed by the broker service.

Task 3 – Inspecting the Client Configuration

In this task, you will explore the client configuration used to create the new service job (also referred to as session).

  1. In the Solution Explorer window, expand the Client project node.

    Figure 2

    The Client project

  2. In the Client project, open the app.config file and locate the <appSettings> XML element:

    C#

    <appSettings> <add key="HeadNodeName" value="MyHeadNode"/> <add key="SoaServiceName" value="SquareService"/> <add key="NodeGroup" value="AzureWorkerNodes"/> </appSettings>

  3. Set the HeadNodeName key to match your head node’s machine name. If you intend to test this sample with on-premises nodes in addition to Windows Azure nodes, change the name of the NodeGroup key to name of the required nodes group.
    Note:
     There is no need to change the SoaServiceName key as this attribute is currently set to the name of the tested service, which is SquareService.

Task 4 – Inspecting the Client Code for an Interactive Session

In this task, you will examine the client code that creates an interactive session and then calls the hosted WCF service in the HPC cluster. Interactive sessions are service jobs that host WCF services in the HPC cluster, and allow interaction with the services through the WCF broker node that routes requests and responses from the client to the cluster and back.

  1. In the Client project open the Program.cs file, and locate the CreateSessionAndCall method.
  2. The CreateSessionAndCall method creates a new Microsoft.Hpc.Scheduler.Session.SessionStartInfoobject and then sets its properties, as shown in the following code snippet:

    C#

    // The name of the head node in the cluster. string schedulerName = ConfigurationManager.AppSettings["HeadNodeName"]; // The name of the called service. string serviceName = ConfigurationManager.AppSettings["SoaServiceName"]; SessionStartInfo info = new SessionStartInfo(schedulerName, serviceName); info.Secure = false; info.NodeGroupList.Add( ConfigurationManager.AppSettings["NodeGroup"]);

    Note:
     You can also set other properties of the SessionStartInfo object to configure how the job executes. For instance, you can set the SessionResourceUnitType property to SessionUnitType.Cores and then set the MinimumUnits and MaximumUnits to define how many cores will be available for each hosted service.

  3. After setting the session start information, the CreateSessionAndCall method creates a new session object using the Microsoft.HPC.Scheduler.Session.Session class, and then calls a delegate that uses the session to send requests to the service, as shown in the following code snippet:

    C#

    using (Session session = Session.CreateSession(info)) { Console.WriteLine("Session ID: " + session.Id); serviceCallDelegate(session); Console.WriteLine("Done retrieving {0} responses\n", _numOfRequests); // Close connections and delete messages stored in the system session.Close(); }

    The Session class is responsible for creating a new job with a service task in the job scheduler. Once the session starts, the client application can send service requests to the WCF broker node that will route them to the available WCF services in the HPC cluster.

  4. In order to call the WCF broker node, the CreateSessionAndCall method calls one of the following delegates:

    Note:
    Note: The CreateSessionAndCall method receives the delegate as a parameter from the program’s static Main method.

    1. InteractiveUsingServiceReference. Calls the WCF broker node using the generated service reference proxy.
    2. InteractiveUsingBrokerClient. Calls the WCF broker node using the BrokerClient<T> generic class.
  5. In the Program.cs file, locate the InteractiveUsingServiceReference method and examine its contents. This method uses the service reference class created for the square service to call the service asynchronously and print out the responses returned by the service, as shown in the following code snippet:

    C#

    int count = 0; AutoResetEvent done = new AutoResetEvent(false); SquareServiceClient proxy = new SquareServiceClient( new NetTcpBinding(SecurityMode.None), session.NetTcpEndpointReference); proxy.SquareCompleted += (sender, e) => { try { int reply = e.Result.SquareResult; Console.WriteLine("Received response for request {0}: {1}", e.UserState, reply); } catch (SessionException ex) { Console.WriteLine("SessionException while getting responses in callback {0}", ex.Message); } catch (Exception ex) { Console.WriteLine("Exception while getting responses in callback: {0}", ex.Message); } if (Interlocked.Increment(ref count) == _numOfRequests) { done.Set(); } }; // start to send requests Console.WriteLine("Sending {0} requests...", _numOfRequests); for (int i = 0; i < _numOfRequests; i++) { proxy.SquareAsync(new SquareRequest(1000 + i), i); } // Main thread block here waiting for the retrieval process // to complete. As the thread that receives the "_numOfRequests" // responses does a Set() on the event, "done.WaitOne()" will pop done.WaitOne();

    Note:
     The client’s proxy uses NetTcpBinding with no security. If you change the proxy to use transport security, you will also need to change the SessionStartInfo.Secure property to true. You cannot use bindings other than the NetTcp binding.

  6. Next, locate the InteractiveUsingBrokerClient method. This method works in a similar way as the previous method, only this time the BrokerClient<T> generic class is used to call the service.

    Note:
     The generic argument T of the BrokerClient<T> class is the service’s contract type.

    1. To register to the service request’s callback method, call the BrokerClient<T>.SetResponseHandler<TMessage> generic method, where TMessage is the type of the message class representing the response type of the called service operation, as shown in the following code snippet:

      C#

      client.SetResponseHandler<SquareResponse>((response) => { try { int reply = response.Result.SquareResult; Console.WriteLine( "Received response for request {0}: {1}", response.GetUserData<int>(), reply); } catch (SessionException ex) { Console.WriteLine( "SessionException while getting responses in callback: {0}", ex.Message); } catch (Exception ex) { Console.WriteLine( "Exception while getting responses in callback: {0}", ex.Message); } if (Interlocked.Increment(ref count) == _numOfRequests) { done.Set(); } });
      Note:
       The message classes were created by the Add Service Reference tool in Visual Studio 2010 by checking the Always generate message contract checkbox in the Service Reference Settings window (accessible by clicking the Advanced… button in the Add Service Reference window).

    2. To send a request to the service, you call the BrokerClient<T>.SendRequest<TMessage> generic method, where TMessage is the type of the message class containing the parameters required by the service operation, as shown in the following code snippet:

      C#

      // start to send requests Console.WriteLine("Sending {0} requests...", _numOfRequests); for (int i = 0; i < _numOfRequests; i++) { client.SendRequest<SquareRequest>(new SquareRequest(1000 + i), i); } client.EndRequests();

Task 5 – Inspecting the Client Code for a Durable Session

In this task, you will examine the client code that creates a durable session, sends requests to the WCF service hosted in the HPC cluster, and then reconnects to the session to retrieve the responses returned by the hosted services. Durable sessions are different from interactive sessions by the fact that the WCF broker queues the responses the WCF service return, thus allowing clients to disconnect from the session after sending requests to the WCF broker node, and later on reconnect to the durable session and retrieve the responses.

  1. In the Client project’s Program.cs file, locate the CreateDurableSessionAndCall method and examine its contents.
  2. This method also uses the Microsoft.Hpc.Scheduler.Session.SessionStartInfotype to define how to start the session, but this time the session is a durable session, created by the Microsoft.Hpc.Scheduler.Session.DurableSession.CreateSessionmethod, as shown in the following code snippet:

    C#

    using (DurableSession session = DurableSession.CreateSession(info)) { sessionId = session.Id; Console.WriteLine("Session ID: " + sessionId); serviceCallDelegate(session); Console.WriteLine("Done sending {0} requests", _numOfRequests); }

  3. After creating the session and sending requests to the service, the session object is disposed, but the durable session keeps running in the job scheduler, collecting responses from the running services. To connect to the running session, the DurableSession.AttachSession method is called with an object of type Microsoft.Hpc.Scheduler.Session.SessionAttachInfo that contains the ID of the running durable session, as shown in the following code snippet:

    C#

    SessionAttachInfo attachInfo = new SessionAttachInfo(schedulerName, sessionId); Console.WriteLine("Attaching to session {0}...", sessionId); // Attach to an already running session using (DurableSession session = DurableSession.AttachSession(attachInfo)) { serviceReceiveDelegate(session); // Close the session to reclaim the system storage // used to store the results. After the session is closed // you cannot attach to the same session again session.Close(); }

  4. In the Program.cs file, locate the DurableSendUsingBrokerClient method and examine its contents. This method performs the same action as the InteractiveUsingServiceReference method, but does not register to the callback. Instead, a different method will handle the response, after the client reattaches to the session.
  5. Locate the DurableReceiveUsingBrokerClient method. This method creates a BrokerClient<T> object and then iterates the service responses received from the WCF broker node by calling the BrokerClient<T>.GetResponses<TMessage> generic method. In this method, TMessage is the type of the message class representing the response type of the called service operation, as shown in the following code snippet:

    C#

    // Create a client proxy using (BrokerClient<ISquareService> client = new BrokerClient<ISquareService>(session)) { Console.WriteLine("Retrieving results..."); // Get all the results foreach (BrokerResponse<SquareResponse> response in client.GetResponses<SquareResponse>()) { int reply = response.Result.SquareResult; Console.WriteLine( "\tReceived response for request {0}: {1}", response.GetUserData<int>(), reply); } Console.WriteLine("Done retrieving results."); }

  6. Build the SquareService solution.