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 are 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.

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 at this link.

Define 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 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 that 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 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 yourself a bit more about the configuration updates, I would suggest having a look at that.

Okay Service Portion has been done. Now, let's move at the 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 Service Client

    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 anything 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 the 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:

References

原文:http://www.codeproject.com/Articles/613677/WebSocket-in-WCF

继承DuplexClientBase类,初始化时关联WCF,并进行业务扩展。

WCF提供相关的数据服务和回调接口,通过OperationContext.Current.GetCallbackChannel获取通道对象,调用回调方法。

WCF websocket的更多相关文章

  1. 如何使用HTML5的WebSocket实现网页与服务器的双工通信(二)

    本系列服务端双工通信包括两种实现方式:一.使用Socket构建:二.使用WCF构建.本文为使用WCF构建服务端的双工通信,客户端同样使用Html5的WebSocket技术进行调用. 一.创建WCF服务 ...

  2. 在WCF中使用websocket

    今天在网上闲逛的时候,发现WCF4.5中新增了一个NetHttpBinding协议,它是支持Websocket的.在网上找了一下教程,附上codeproject上的两篇文章: http://www.c ...

  3. WCF学习之旅—WCF概述(四)

    一.WCF概述 1) 什么是WCF? Windows Communication Foundation (WCF) 是用于构建面向服务的应用程序的框架.借助 WCF,可以将数据作为异步消息从一个服务终 ...

  4. http与websocket(基于SignalR)两种协议下的跨域基于ASP.NET MVC--竹子整理

    这段时间,项目涉及到移动端,这就不可避免的涉及到了跨域的问题.这是本人第一次接触跨域,有些地方的配置是有点麻烦,导致一开始的不顺. 至于websocket具体是什么意义,用途如何:请百度. 简单说就是 ...

  5. 【转】WCF和ASP.NET Web API在应用上的选择

    文章出处:http://www.cnblogs.com/shanyou/archive/2012/09/26/2704814.html 在最近发布的Visual Studio 2012及.NET 4. ...

  6. ASP.NET Web API——选择Web API还是WCF

    WCF是.NET平台服务开发的一站式框架,那么为什么还要有ASP.NET Web API呢?简单来说,ASP.NET Web API的设计和构建只考虑了一件事情,那就是HTTP,而WCF的设计主要是考 ...

  7. WCF和ASP.NET Web API在应用上的选择

    小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/shareto ...

  8. Web、WCF和WS通过Nginx共享80端口

    团队中的一个Web项目面对的用户网络环境多是在严格的防火墙安全条件下,通常只开放一些标准的端口如80,21等. 上线初期,因忽略了这个问题,除了Web应用是以80端口提供访问外,WCF和WS是以其他端 ...

  9. 如何使用HTML5的WebSocket实现网页与服务器的双工通信(一)

    本系列服务端双工通信包括两种实现方式:一.使用Socket构建:二.使用WCF构建.本文为使用Socket构建服务端的双工通信,客户端同样使用Html5的WebSocket技术进行调用. 一.网页客户 ...

随机推荐

  1. 3月6日 c#语言

    语言基础 一.输入与输出 1.Main函数: static void Main(string [] args) { }程序代码需要写在Main函数的花括号内. 2.输出: Console.Write( ...

  2. PHP二维数组排序函数

    PHP一维数组的排序可以用sort(),asort(),arsort()等函数,但是PHP二维数组的排序需要自定义. 以下函数是对一个给定的二维数组按照指定的键值进行排序,先看函数定义: functi ...

  3. linux清理僵尸进程

    查看服务器时发现好3个僵尸进程,僵尸进程存在好多天了,一直不会处理,留到了今天,顺便清理下僵尸进程吧 top命令中统计了僵尸进程,是第二行最后一项3 zombie. 或者使用下面的命令得到僵尸进程数量 ...

  4. Python学习笔记总结(四)异常处理

    1.基础 try/except/else:[else是可选的]捕捉由代码中的异常并恢复,匹配except里面的错误,并执行except中定义的代码,后继续执行程序(发生异常后,由except捕捉到异常 ...

  5. [LeetCode 121] - 买入与卖出股票的最佳时机(Best Time to Buy and Sell Stock)

    问题 假设你有一个数组,其中的第i个元素表示一只股票在第i天的价格. 如果只允许你完成一次交易(即买入并卖出股票一次),设计一个找出最大利润的算法. 初始思路 和122一样,基于买入与卖出股票的最佳时 ...

  6. bat命令大全

    一.简单批处理内部命令简介 1.Echo 命令 打开回显或关闭请求回显功能,或显示消息.如果没有任何参数,echo 命令将显示当前回显设置.   语法 echo [{on│off}] [message ...

  7. 哪些产品不用开发原生APP,微信公众号就够了?

    最近一阶段H5技术被推到高峰,很多人认为借助H5就能利用微信公众号取代APP原生应用了,而事实是怎么样的?这里我从产品层做一个客观分析. 一,原生APP总体趋势 要谈APP是否会被微信取代,那么必须回 ...

  8. #include"*.c" 文件问题

    一般我们学习C语言的时候,include预编译的一般是.h头文件,虽然来说#include却是可以包含任意扩展名的文件,因为考虑到接口与实现分离的问题,头文件里面一般放函数,变量等声明,大家一般都推荐 ...

  9. Linux企业级项目实践之网络爬虫(15)——区分文本文件和二进制文件

    HTTP协议支持文本和二进制文件传输.最常见的html格式的页面即文本,图片.音乐等为二进制文件.我们要对这两类文件加以区分并分别处理. static char * BIN_SUFFIXES = &q ...

  10. 怎样用jQuery自带方法/函数来获取outerHTML属性

    原文地址:http://jingyan.baidu.com/article/7f41ececf93b48593d095c25.html 包括我自己在内(其实我也就这两天才知道这样可以快速获取的),很多 ...