Rashim's Blog

Archive for June 2013


WebSocket, like as TCP, is a bi-directional, full-duplex communication channel over a single TCP connection but it shortens abundant complications close to bi-directional communication as well as connection management which we typically comprehend while using TCP. WebSocket channels start as normal HTTP channels which then upgraded to WebSocket channels by using handshaking, allowing cooperative TCP communication between client and server.

WCF hosts provision for WebSockets over the standard HTTP ports 80 and 443. The standard HTTP port allows WebSockets to communicate across the web through mediators. WCF introduces two standard bindings to support communication over a WebSocket transport.

  • NetHttpBinding
  • NetHttpsBinding

These bindings are designed for consuming WebSocket services and will perceive whether they are used with a request-reply contract or duplex contract and change their behavior according to it. They will use HTTP/HTTPS for request-reply contracts and WebSockets for duplex contracts. We can override this behavior by using WebSocketTransportUsage setting

  • Always – Enforce to use WebSockets.
  • Never – Stops to use WebSockets.
  • WhenDuplex – This is the default value.

Let’s move into the code to see how we could implement WCF service and clients that will communicate over WebSockets.

Define callback Contract

    public interface INotificationServiceCallback
    {
        [OperationContract(IsOneWay = true)]
        void OnNotificationSend(Notification notification);
    }

Clients will implement this contract through which the service can send messages back to the clients. To have a better understanding how duplex channel works I would recommend you to have a look on this link.

Define the service contract

    [ServiceContract(CallbackContract = typeof(INotificationServiceCallback))]
    public interface INotificationService
    {
        [OperationContract]
        void SendNotification(Notification notification);

        [OperationContract]
        void SubscribeForNotification(List<NotificationType> notificationTypes);

        [OperationContract]
        void UnsubscribeForNotification(List<NotificationType> notificationTypes);
    }

Here INotificationServiceCallback has been specified as the callback contract.

Implement the service contract

    public class NotificationServiceService : INotificationService
    {
        private INotificationServiceCallback Subscriber
        {
            get { return OperationContext.Current.GetCallbackChannel<INotificationServiceCallback>();  }
        }

        public void SendNotification(Notification notification)
        {
            NotificationManager.Instance.SendNotification(notification, Subscriber);
        }

        public void SubscribeForNotification(List<NotificationType> notificationTypes)
        {
            NotificationManager.Instance.AddSubscriber(Subscriber, notificationTypes);
        }

        public void UnsubscribeForNotification(List<NotificationType> notificationTypes)
        {
            NotificationManager.Instance.RemoveSubscriber(Subscriber, notificationTypes);
        }
    }

In the implementation, we retain the callback channel using the OperationContext which has been passed to the NotificationManager and finally NotificationManager does the rest of the Jobs.

Implement Notification Manager

    public class NotificationManager
    {
        private volatile static NotificationManager _notificationManager = null;
        private static readonly object SyncLock = new object();
        private NotificationManager()
        {
            Subscribers = new Dictionary<INotificationServiceCallback, List<NotificationType>>();
            Notifications = new List<Notification>();
        }

        public Dictionary<INotificationServiceCallback, List<NotificationType>> Subscribers { get; private set; }
        public List<Notification> Notifications { get; private set; }
        public static NotificationManager Instance
        {
            get
            {
                lock (SyncLock)
                {
                    if (_notificationManager == null)
                    {
                        lock (SyncLock)
                        {
                            _notificationManager = new NotificationManager();
                        }
                    }
                }
                return _notificationManager;
            }
        }

        public void AddSubscriber(INotificationServiceCallback subscriber, List<NotificationType> notificationType)
        {
            if (!Subscribers.ContainsKey(subscriber))
                Subscribers.Add(subscriber, notificationType);
            else
            {
                var newNotificationType = notificationType.Where(n => Subscribers[subscriber].Any(n1 => n1 != n));
                Subscribers[subscriber].AddRange(newNotificationType);
            }
        }

        public void RemoveSubscriber(INotificationServiceCallback subscriber, List<NotificationType> notificationTypes)
        {
            if (Subscribers.ContainsKey(subscriber))
            {
                notificationTypes.ForEach(notificationType => Subscribers[subscriber].Remove(notificationType));

                if (Subscribers[subscriber].Count < 1)
                    Subscribers.Remove(subscriber);
            }
        }

        public void AddNotification(Notification notification)
        {
            if (!Notifications.Contains(notification))
                Notifications.Add(notification);
        }

        public void RemoveNotification(Notification notification)
        {
            if (Notifications.Contains(notification))
                Notifications.Remove(notification);

        }

        public void SendNotification(Notification notification, INotificationServiceCallback sender)
        {
            foreach (var existingSubscriber in Subscribers)
            {
                if (existingSubscriber.Value.Any(n => n == notification.NotificationType) && existingSubscriber.Key != sender)
                {
                    if (((ICommunicationObject)existingSubscriber.Key).State == CommunicationState.Opened)
                    {
                        existingSubscriber.Key.OnNotificationSend(notification);
                    }
                }
            }
        }
    }

As we see, NotificationManager maintains a dictionary to hold the client list whose have been subscribed for getting the notifications for different notification types. If any client broadcast messages with Notification types, the subscribers who only subscribe to get the notification for these notification types will get these messages. The code is itself self-explanatory. If you go through on the code portion you will easily have an idea about that.

Service configuration

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
     <compilation debug="true" targetFramework="4.5" />
     <httpRuntime targetFramework="4.5" />
  </system.web>
   <system.serviceModel>
        <protocolMapping>
          <add scheme="http" binding="netHttpBinding" />
        </protocolMapping>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <directoryBrowse enabled="true" />
    </system.webServer>
</configuration>

NetHttpBinding has been used for the default endpoints. If you want to acquaint a bit more about the configuration updates, I would suggest having a look on that.

Okay Service Portion has been done. Now, lets move to client portions,

Implement callback contract and Define Client

    class Program : INotificationServiceCallback
    {
        private NotificationServiceClient _notificationServiceClient;
        private InstanceContext _instanceContext;
        private readonly List<NotificationType> _notificationTypes = Enum.GetValues(typeof(NotificationType)).Cast<NotificationType>().ToList();

        public NotificationServiceClient NotificationServiceClient
        {
            get
            {
                return _notificationServiceClient ??
                       (_notificationServiceClient = new NotificationServiceClient(CallbackInstance,
                                                                                   "netHttpBinding_INotificationService"));
            }
        }

        public InstanceContext CallbackInstance
        {
            get { return _instanceContext ?? (_instanceContext = new InstanceContext(this)); }
        }

        static void Main(string[] args)
        {
            var objProgram = new Program();
            Console.WriteLine("Write exit to shut down....\n");
            Console.WriteLine("Wait...Subscribing for notifications\n");
            objProgram.SubscribeForNotification();
            Console.WriteLine("Subscription done...Now you can send notifacation\n");
            var readMsg = Console.ReadLine();

            while (readMsg.ToString(CultureInfo.InvariantCulture).ToLower().Equals("exit") == false)
            {
                objProgram.SendNotification(readMsg);
                Console.WriteLine("Notification has been send......\n");
                readMsg = Console.ReadLine();
            }
            objProgram.UnsubscribeForNotification();
        }

        public void OnNotificationSend(Notification notification)
        {
            Console.WriteLine(string.Format("New Notification Received\n\nMessage :{0}\nTime :{1}\n\n", notification.NotificationMsg, notification.PostingTime));
        }

        private void SubscribeForNotification()
        {
            NotificationServiceClient.SubscribeForNotification(_notificationTypes);
        }

        private void UnsubscribeForNotification()
        {
            NotificationServiceClient.UnsubscribeForNotification(_notificationTypes);
        }

        private void SendNotification(string msg)
        {
            NotificationServiceClient.SendNotification(new Notification()
            {
                NotificationMsg = msg,
                PostingTime = DateTime.Now
            });
        }
    }

The client application has a property of InstanceContext and NotificationServiceClient, also it specifies the implementation of the INotificationServiceCallback interface. When a client subscribes for the notifications to the service, the service will send the notifications to the client using the callback contract specified.

Implement NotificationServiceClient

    public class NotificationServiceClient : DuplexClientBase<INotificationService>, INotificationService
    {
        public NotificationServiceClient(InstanceContext callbackInstance) :
            base(callbackInstance)
        {
        }

        public NotificationServiceClient(InstanceContext callbackInstance, string endpointConfigurationName) :
            base(callbackInstance, endpointConfigurationName)
        {
        }

        public void SendNotification(Notification notification)
        {
            Channel.SendNotification(notification);
        }

        public void SubscribeForNotification(List<NotificationType> notificationTypes)
        {
            Channel.SubscribeForNotification(notificationTypes);
        }

        public void UnsubscribeForNotification(List<NotificationType> notificationTypes)
        {
            Channel.UnsubscribeForNotification(notificationTypes);
        }
    }

Client Configuration

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <bindings>
      <netHttpBinding>
        <binding name="NetHttpBinding_INotificationService">
          <webSocketSettings transportUsage="Always" />
        </binding>
      </netHttpBinding>
    </bindings>
    <client>
      <endpoint address="ws://localhost/websocket/NotificationService.svc"
          binding="netHttpBinding"
          contract="Rashim.RND.WCF.WebSockect.Interfaces.INotificationService"
             bindingConfiguration="NetHttpBinding_INotificationService"
          name="netHttpBinding_INotificationService">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

This is as usual and not any special, what you need to do in the client configuration is to specify the client side endpoint using the NetHttpBinding.

Finally DataContracts

    [DataContract]
    public class Notification
    {
        [DataMember]
        public string NotificationMsg { get; set; }
        [DataMember]
        public DateTime PostingTime { get; set; }
        [DataMember]
        public NotificationType NotificationType { get; set; }
    }
    [DataContract]
    public enum NotificationType
    {
        [EnumMember]
        General,
        [EnumMember]
        Greetings
    }

Using Source code

You need to host the Rashim.RND.WCF.WebSockect.Services in IIS8 and then put the appropriate endpoint address to the client configuration file. After completing the Service hosting, you need to run the two instances of Rashim.RND.WCF.WebSockect.Clients then you can send message from instance to another one just like the given figure below.

WebSocketDemo
 References: 

Download SourceCode.

 
Advertisements

Sometimes client applications need to retrieve different types of file (.doc, .xls, .zip…etc.) from web application to do some of their internal works or even just for the users. So, if we could make such web application which provides the facility to the client applications to download different files from the server, we don’t need to change or modify the code of the web application each time we upload the different types of file to the server.

This can be easily achieved by using an HTTP Handler for download operation. We can use normal asp.net web page for this purposes, but the reason behind to choose an HTTP Handler is only for performance issues. Firstly, we get benefit of scalability as we don’t need to show any output value to the page. Secondly, an HTTP handler doesn’t go through the full page events which ultimately improve performance.

The handler code has given below which is self-descriptive and requires no more description,

public class Download : IHttpHandler
{
 public bool IsReusable
 {
    get
    {
     return false;
    }
 }

 public void ProcessRequest(HttpContext context)
 {
    var request = context.Request;
    Stream stream = null;
    var buffer = new byte[2048];
    var fileName = request["FileName"];

    if (string.IsNullOrEmpty(fileName))
       throw new Exception("File name is Empty");

    var fullFileName = Path.Combine(string.Format("{0}", request.PhysicalApplicationPath), "DownloadFiles",fileName);
    try
    {
       stream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
       var dataToRead = stream.Length;
       while (dataToRead > 0)
       {
          if (context.Response.IsClientConnected)
          {
             var length = stream.Read(buffer, 0, 2048);
             context.Response.OutputStream.Write(buffer, 0, length);
             context.Response.Flush();
             buffer = new byte[2048];
             dataToRead = dataToRead - length;
          }
          else
          {
             dataToRead = -1;
          }
       }
    }
    catch (Exception ex)
    {
       context.Response.Write(ex);
    }
    finally
    {
       if (stream != null)
       {
          stream.Close();
       }
    }
  }
}

The client applications need to send a request to the download handler appending the Filename variable in the QueryString. This is also a laid-back substance. I am giving a sample code for that,

 var fileName = string.Format("{0}","Install.zip");
 var queryString = string.Format("{0}{1}{2}", "FileName", "=", fileName);
 var downloadUrl = URL of Download.ashx;
 var url = string.Format("{0}{1}{2}", downloadUrl,"?", queryString);
 var downBuffer = new byte[2048];

 var webRequest = (HttpWebRequest)WebRequest.Create(url);
 webRequest.KeepAlive = false;
 webRequest.UnsafeAuthenticatedConnectionSharing = true;
 webRequest.Credentials = CredentialCache.DefaultCredentials;
 var webResponse = (HttpWebResponse)webRequest.GetResponse();
 var streamResponse = webResponse.GetResponseStream();
 var fileStream = new FileStream(string.Format("{0}{1}", "D:\\", fileName), FileMode.Create, FileAccess.Write);

 if (streamResponse != null)
 {
     int bytesRead;
     while ((bytesRead = streamResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
     {
         fileStream.Write(downBuffer, 0, bytesRead);
     }
 }

 fileStream.Close();

Here, I host the web application to the local IIS and the URL for download handler is ‘…/Download.ashx’. WebRequest is for making a request to a URI and HttpWebRequest offers an HTTP specific operation of WebRequest where HttpWebResponse delivers a response from a URI.

Download SourceCode


%d bloggers like this: