Exercise: WindowsAzureRoleCommunicationVS2010Lab

Using Worker Role External Endpoints

worker role to host a WCF service at the external endpoint.


1) Add External Endpoint on Worker Role

2) Host WCF service base on the External Endpoint defined at the step 1)



// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------

namespace WindowsAzurePlatformKit.AzureTalk.Service
{
    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Net;
    using System.ServiceModel;
    using System.Threading;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.Diagnostics;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using WindowsAzurePlatformKit.AzureTalk.Contract;

    public class WorkerRole : RoleEntryPoint
    {
        private ServiceHost serviceHost;

        public override void Run()
        {
            Trace.TraceInformation("AzureTalk.Service entry point called");

            this.StartChatService(3);

            while (true)
            {
                Thread.Sleep(300000);
                Trace.TraceInformation("Working", "Information");
            }
        }

        public override bool OnStart()
        {
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;
            
            return base.OnStart();
        }

        /// <summary>
        /// Starts the service host object for the internal 
        /// and external endpoints of the chat service.
        /// </summary>
        /// <param name="retries">Specifies the number of retries to 
        /// start the service in case of failure.</param>
        private void StartChatService(int retries)
        {
            // recycle the role if host cannot be started 
            // after the specified number of retries
            if (retries == 0)
            {
                RoleEnvironment.RequestRecycle();
                return;
            }

            Trace.TraceInformation("Starting chat service host...");

            this.serviceHost = new ServiceHost(typeof(ChatService));

            // Recover the service in case of failure. 
            // Log the fault and attempt to restart the service host. 
            this.serviceHost.Faulted += (sender, e) =>
            {
                Trace.TraceError("Host fault occured. Aborting and restarting the host. Retry count: {0}", retries);
                this.serviceHost.Abort();
                this.StartChatService(--retries);
            };

            // use NetTcpBinding with no security
            NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);

            // define an external endpoint for client traffic
            RoleInstanceEndpoint externalEndPoint =
                RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["ChatService"];

            this.serviceHost.AddServiceEndpoint(
               typeof(IChatService),
               binding,
               String.Format("net.tcp://{0}/ChatService", externalEndPoint.IPEndpoint));

            try
            {
                this.serviceHost.Open();
                Trace.TraceInformation("Chat service host started successfully.");
            }
            catch (TimeoutException timeoutException)
            {
                Trace.TraceError("The service operation timed out. {0}",
                                 timeoutException.Message);
            }
            catch (CommunicationException communicationException)
            {
                Trace.TraceError("Could not start chat service host. {0}",
                                 communicationException.Message);
            }
        }
    }
}

Using Internal Endpoints for Inter-Role Communication

So far, even though multiple instances of the worker role can each host its own endpoint for the chat service, they all operate as independent servers. Clients connected to a given instance are unable to exchange messages with peers in other worker role instances because roles do not share session information.

1) Add External Endpoint and Internal Endpoint on Worker Role

2) Host 2 WCF service base on the External Endpoint and Internal Endpoint defined at the step 1)



// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------

namespace WindowsAzurePlatformKit.AzureTalk.Service
{
    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Net;
    using System.ServiceModel;
    using System.Threading;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.Diagnostics;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using WindowsAzurePlatformKit.AzureTalk.Contract;

    public class WorkerRole : RoleEntryPoint
    {
        /// <summary>Channel factory for inter-role notifications.</summary>
        private static ChannelFactory<IClientNotification> factory;
        /// <summary>ServiceHost object for internal and external endpoints.</summary>
        private ServiceHost serviceHost;

        public override void Run()
        {
            Trace.TraceInformation("AzureTalk.Service entry point called");

            this.StartChatService(3);

            while (true)
            {
                Thread.Sleep(300000);
                Trace.TraceInformation("Working", "Information");
            }
        }

        public override bool OnStart()
        {
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;
            
            return base.OnStart();
        }

        /// <summary>
        /// Starts the service host object for the internal 
        /// and external endpoints of the chat service.
        /// </summary>
        /// <param name="retries">Specifies the number of retries to 
        /// start the service in case of failure.</param>
        private void StartChatService(int retries)
        {
            // recycle the role if host cannot be started 
            // after the specified number of retries
            if (retries == 0)
            {
                RoleEnvironment.RequestRecycle();
                return;
            }

            Trace.TraceInformation("Starting chat service host...");

            this.serviceHost = new ServiceHost(typeof(ChatService));

            // Recover the service in case of failure. 
            // Log the fault and attempt to restart the service host. 
            this.serviceHost.Faulted += (sender, e) =>
            {
                Trace.TraceError("Host fault occured. Aborting and restarting the host. Retry count: {0}", retries);
                this.serviceHost.Abort();
                this.StartChatService(--retries);
            };

            // use NetTcpBinding with no security
            NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);

            // define an external endpoint for client traffic
            RoleInstanceEndpoint externalEndPoint =
                RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["ChatService"];

            this.serviceHost.AddServiceEndpoint(
               typeof(IChatService),
               binding,
               String.Format("net.tcp://{0}/ChatService", externalEndPoint.IPEndpoint));

            // define an internal endpoint for inter-role traffic
            RoleInstanceEndpoint internalEndPoint =
                RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["NotificationService"];
            this.serviceHost.AddServiceEndpoint(
               typeof(IClientNotification),
               binding,
               String.Format("net.tcp://{0}/NotificationService", internalEndPoint.IPEndpoint));

            // create channel factory for inter-role communication
            WorkerRole.factory = new ChannelFactory<IClientNotification>(binding);

            try
            {
                this.serviceHost.Open();
                Trace.TraceInformation("Chat service host started successfully.");
            }
            catch (TimeoutException timeoutException)
            {
                Trace.TraceError("The service operation timed out. {0}",
                                 timeoutException.Message);
            }
            catch (CommunicationException communicationException)
            {
                Trace.TraceError("Could not start chat service host. {0}",
                                 communicationException.Message);
            }
        }

        /// <summary>
        /// Notifies all available worker roles to update their active sessions list 
        /// when a new client connects or disconnects.
        /// </summary>
        /// <param name="session">The SessionInformation object for the client.</param>
        internal static void NotifyAllNodes(SessionInformation session)
        {
            // iterate over all instances of the internal endpoint except the current role - no need to notify itself
            var current = RoleEnvironment.CurrentRoleInstance;
            var endPoints = current.Role.Instances
                            .Where(instance => instance != current)
                            .Select(instance => instance.InstanceEndpoints["NotificationService"]);

            foreach (var ep in endPoints)
            {
                EndpointAddress address =
                    new EndpointAddress(String.Format("net.tcp://{0}/NotificationService", ep.IPEndpoint));
                IClientNotification client = WorkerRole.factory.CreateChannel(address);

                try
                {
                    client.UpdateClientList(session);
                    ((ICommunicationObject)client).Close();
                }
                catch (TimeoutException timeoutException)
                {
                    Trace.TraceError("Unable to notify worker role instance '{0}'. The service operation timed out. {1}", ep.RoleInstance.Id, timeoutException.Message);
                    ((ICommunicationObject)client).Abort();
                }
                catch (CommunicationException communicationException)
                {
                    Trace.TraceError("Unable to notify worker role instance '{0}'. There was a communication problem. {1} - {2}", ep.RoleInstance.Id, communicationException.Message, communicationException.StackTrace);
                    ((ICommunicationObject)client).Abort();
                }
            }
        }

        /// <summary>
        /// Forwards a message from the current role to the role of the destination session.
        /// </summary>
        /// <param name="message">The message to forward.</param>
        /// <param name="fromSessionId">The ID of the source session.</param>
        /// <param name="toSessionId">The ID of the target session.</param>
        public static void ForwardMessage(string message, string fromSessionId, string toSessionId)
        {
            SessionInformation session = SessionManager.GetSession(toSessionId);
            if (session == null)
            {
                return;
            }

            // retrieve the endpoint for the role instance where the target session is active
            var targetRole = RoleEnvironment.CurrentRoleInstance.Role.Instances
                             .Where(role => role.Id == session.RoleId).FirstOrDefault();
            if (targetRole != null)
            {
                var ep = targetRole.InstanceEndpoints["NotificationService"];
                if (ep != null)
                {
                    EndpointAddress address =
                        new EndpointAddress(String.Format("net.tcp://{0}/NotificationService", ep.IPEndpoint));

                    IClientNotification client = WorkerRole.factory.CreateChannel(address);
                    try
                    {
                        client.DeliverMessage(message, fromSessionId, toSessionId);
                        ((ICommunicationObject)client).Close();
                    }
                    catch (TimeoutException timeoutException)
                    {
                        Trace.TraceError("Unable to forward message to instance '{0}'. The service operation timed out. {1}", ep.RoleInstance.Id, timeoutException.Message);
                        ((ICommunicationObject)client).Abort();
                    }
                    catch (CommunicationException communicationException)
                    {
                        Trace.TraceError("Unable to forward message to instance '{0}'. There was a communication problem. {1} - {2}", ep.RoleInstance.Id, communicationException.Message, communicationException.StackTrace);
                        ((ICommunicationObject)client).Abort();
                    }
                }
            }
        }
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值