WCF websocket
2016-05-25 13:46
323 查看
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.
WebSocketchannels start as normal HTTP channels which are then upgraded to
WebSocketchannels by using handshaking, allowing cooperative TCP communication between client and server.
WCF hosts provision for
WebSocketsover the standard HTTP ports 80 and 443. The standard HTTP port allows
WebSocketsto communicate across the web through mediators. WCF introduces two standard bindings to support communication over a
WebSockettransport.
NetHttpBinding
NetHttpsBinding
These bindings are designed for consuming
WebSocketservices 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
WebSocketsfor duplex contracts. We can override this behavior by using
WebSocketTransportUsagesetting:
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,
INotificationServiceCallbackhas been specified as the callback contract.
Implement Service Contract
public class NotificationServiceService : INotificationService
{
private INotificationServiceCallbackSubscriber
{
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
OperationContextwhich has been passed to the
NotificationManagerand finally
NotificationManagerdoes 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 NotificationManagerInstance
{
get
{
lock (SyncLock)
{
if (_notificationManager == null)
{
lock (SyncLock)
{
_notificationManager = new NotificationManager();
}
}
}
return _notificationManager;
}
}
public void AddSubscriber(INotificationServiceCallbacksubscriber,
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, INotificationServiceCallbacksender)
{
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,
NotificationManagermaintains 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>
NetHttpBindinghas 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 InstanceContextCallbackInstance { 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
InstanceContextand
NotificationServiceClient, also it specifies the implementation of the
INotificationServiceCallbackinterface. 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(InstanceContextcallbackInstance) :
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 theRashim.RND.WCF.WebSockect.Servicesin 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://msdn.microsoft.com/en-us/library/hh674271.aspxhttp://msdn.microsoft.com/en-us/library/hh674273.aspx
http://msdn.microsoft.com/en-us/library/hh977020.aspx
http://rashimuddin.wordpress.com/2012/09/30/171/
http://rashimuddin.wordpress.com/2013/04/06/duplex-service-in-wcf/
原文:http://www.codeproject.com/Articles/613677/WebSocket-in-WCF
继承DuplexClientBase类,初始化时关联WCF,并进行业务扩展。
WCF提供相关的数据服务和回调接口,通过OperationContext.Current.GetCallbackChannel获取通道对象,调用回调方法。
相关文章推荐
- android获取拍照图片、本地图片简单实现!
- VC2010快捷
- 代码走读
- Scrum 项目 7.0 Sprint回顾
- linux系统安装jdk8
- c#获取当前日期时间(转)
- Java并发编程:volatile关键字解析
- 模式识别(Pattern Recognition)学习笔记(十四)--多类线性判别函数
- Unicode编码及其实现:UTF-16、UTF-8,and more
- JPA持久化上下文与对象状态
- linux基础命令学习 (十一)系统管理命令
- startActivityForResult与startActivity的不同之处
- C# 串口
- 移动端地图技术分享
- 数据分析与挖掘 - R语言:贝叶斯分类算法(案例二)
- 第10,11周 补充 项目一
- Salt-ssh批量自动安装被控端minion
- 队列的表示
- Yii框架中行为Behavior的概念
- textarea 在浏览器中固定大小和禁止拖动