中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Push Data From Server to Silverlight Clients With a WCF Duplex Service

發布時間:2020-08-10 15:02:48 來源:ITPUB博客 閱讀:159 作者:yuzhangqi 欄目:網絡安全

Normally in a client-server architecture application, the client makes a request to the server, then the server responses to the client. The client side PULLs data from the server side. However, we sometimes want the server side to PUSH data to the client side whenever the data changed. With a WCF duplex service, we can push updated data to Silverlight clients. In the rest of this blog I will show you how to achieve this goal.

Many of the WCF services out there follow the simple request-response mechanism to exchange data which works well for many applications. However, in addition to standard HTTP bindings, WCF also supports several others including a polling duplex binding made specifically for Silverlight which allows a service to push data down to a client as the data changes. This type of binding isn't as "pure" as the push model available with sockets since the Silverlight client does poll the server to check for any queued messages, but it provides an efficient way to push data to a client without being restricted to a specific port range. Once a communication channel is opened messages can be sent in either direction. The Silverlight SDK states the following about how communication works between a Silverlight client and a duplex service:

"The Silverlight client periodically polls the service on the network layer, and checks for any new messages that the service wants to send on the callback channel. The service queues all messages sent on the client callback channel and delivers them to the client when the client polls the service."

I still use a sample application to demonstrate it.

1. Creating Base Contracts

When creating a WCF duplex service for Silverlight, the server creates a standard interface with operations. However, because the server must communicate with the client it also defines a client callback interface. The interfaces are defined as below.

IUniversalDuplexContract

[ServiceContract(Name="DuplexService", CallbackContract = typeof(IUniversalDuplexCallbackContract))]
public interface IUniversalDuplexContract
{
[OperationContract(IsOneWay = true)]
void SendToService(DuplexMessage msg);
}

This interface is a little different from the standard WCF interfaces you may have seen or created. First, it includes a CallbackContract property that points to the client interface. Second, the SendToService() operation is defined as a one way operation. Client calls are not immediately returned as a result of setting IsOneWay to true and are pushed to the client instead.

IUniversalDuplexCallbackContract

[ServiceContract]
public interface IUniversalDuplexCallbackContract
{
//[OperationContract(IsOneWay = true)]
//void SendToClient(DuplexMessage msg);

[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginSendToClient(DuplexMessage msg, AsyncCallback acb, object state);
void EndSendToClient(IAsyncResult iar);
}

The IUniversalDuplexCallbackContract interface allows a message to be sent back to the client by calling the SendToClient() method.

2. Creating Base Duplex Service

Once the server and client contracts are defined a service class can be created that implements the IUniversalDuplexContract interface.

DuplexService

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public abstract class DuplexService : IUniversalDuplexContract
{
object syncRoot = new object();
Dictionary clients = new Dictionary();

///


/// This will be called when a new client is connected
///

/// Session ID of the newly-connected client
protected virtual void OnConnected(string sessionId) { }

///
/// This will be called when a client is disconnected
///

/// Session ID of the newly-disconnected client
protected virtual void OnDisconnected(string sessionId) { }

///


/// This will be called when a message is received from a client
///

/// Session ID of the client sending the message
/// The message that was received
protected virtual void OnMessage(string sessionId, DuplexMessage message) { }

///


/// Pushes a message to all connected clients
///

/// The message to push
protected void PushToAllClients(DuplexMessage message)
{
lock (syncRoot)
{
foreach (string session in clients.Keys)
{
PushMessageToClient(session, message);
}
}
}

///


/// Pushes a message to one specific client
///

/// Session ID of the client that should receive the message
/// The message to push
protected void PushMessageToClient(string clientSessionId, DuplexMessage message)
{
IUniversalDuplexCallbackContract ch = clients[clientSessionId];

IAsyncResult iar = ch.BeginSendToClient(message, new AsyncCallback(OnPushMessageComplete), new PushMessageState(ch, clientSessionId));
if (iar.CompletedSynchronously)
{
CompletePushMessage(iar);
}
}

void OnPushMessageComplete(IAsyncResult iar)
{
if (iar.CompletedSynchronously)
{
return;
}
else
{
CompletePushMessage(iar);
}
}

void CompletePushMessage(IAsyncResult iar)
{
IUniversalDuplexCallbackContract ch = ((PushMessageState)(iar.AsyncState)).ch;
try
{
ch.EndSendToClient(iar);
}
catch (Exception ex)
{
//Any error while pushing out a message to a client
//will be treated as if that client has disconnected
System.Diagnostics.Debug.WriteLine(ex);
ClientDisconnected(((PushMessageState)(iar.AsyncState)).sessionId);
}
}


void IUniversalDuplexContract.SendToService(DuplexMessage msg)
{
//We get here when we receive a message from a client

IUniversalDuplexCallbackContract ch = OperationContext.Current.GetCallbackChannel();
string session = OperationContext.Current.Channel.SessionId;

//Any message from a client we haven't seen before causes the new client to be added to our list
//(Basically, treated as a "Connect" message)
lock (syncRoot)
{
if (!clients.ContainsKey(session))
{
clients.Add(session, ch);
OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing);
OperationContext.Current.Channel.Faulted += new EventHandler(Channel_Faulted);
OnConnected(session);
}
}

//If it's a Disconnect message, treat as disconnection
if (msg is DisconnectMessage)
{
ClientDisconnected(session);
}
//Otherwise, if it's a payload-carrying message (and not just a simple "Connect"), process it
else if (!(msg is ConnectMessage))
{
OnMessage(session, msg);
}
}

void Channel_Closing(object sender, EventArgs e)
{
IContextChannel channel = (IContextChannel)sender;
ClientDisconnected(channel.SessionId);
}

void Channel_Faulted(object sender, EventArgs e)
{
IContextChannel channel = (IContextChannel)sender;
ClientDisconnected(channel.SessionId);
}

void ClientDisconnected(string sessionId)
{
lock (syncRoot)
{
if (clients.ContainsKey(sessionId))
clients.Remove(sessionId);
}
try
{
OnDisconnected(sessionId);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}

//Helper class for tracking both a channel and its session ID together
class PushMessageState
{
internal IUniversalDuplexCallbackContract ch;
internal string sessionId;
internal PushMessageState(IUniversalDuplexCallbackContract channel, string session)
{
ch = channel;
sessionId = session;
}
}
}

The DuplexService can be used as base class of other business services.

3. Creating Base Duplex Service Factory

DuplexServiceFactory

///


/// Derive from this class to create a duplex Service Factory to use in an .svc file
///

/// The Duplex Service type (typically derived from DuplexService)
public abstract class DuplexServiceFactory : ServiceHostFactoryBase
where T : IUniversalDuplexContract, new()
{
T serviceInstance = new T();

///
/// This method is called by WCF when it needs to construct the service.
/// Typically this should not be overridden further.
///

public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
ServiceHost service = new ServiceHost(serviceInstance, baseAddresses);
CustomBinding binding = new CustomBinding(
new PollingDuplexBindingElement(),
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement());

service.Description.Behaviors.Add(new ServiceMetadataBehavior());
service.AddServiceEndpoint(typeof(IUniversalDuplexContract), binding, "");
service.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
return service;
}
}

The factory is responsible for creating the appropriate host while the host defines the service endpoint.

4. Create Base Duplex Message

///


/// Base message class. Please add [KnownType] attributes as necessary for every
/// derived message type.
///

[DataContract(Namespace = "http://samples.microsoft.com/silverlight2/duplex")]
[KnownType(typeof(ConnectMessage))]
[KnownType(typeof(DisconnectMessage))]
[KnownType(typeof(LiveDataMessage))]
public class DuplexMessage { }

Any business objects intend to be pushed from the duplex service to silverlight clients must derive from this DuplexMessage class, and with a [KnownType] attribute.

Now we have constructed the infrastructure of the duplex service. Next Let's create a concrete duplex business service to push business data to silverlight clients.

5. Create a Business Service

LiveDataMessage

[DataContract]
public class LiveDataMessage: DuplexMessage
{
[DataMember]
public int Value { get; set; }
[DataMember]
public string Description { get; set; }
}

LiveDataService

public class LiveDataService :DuplexService
{
Timer liveDataTimer;

public LiveDataService()
{
//Set up a an update every 5 seconds
this.liveDataTimer = new Timer(new TimerCallback(LiveDataUpdate),null, 0, 5000);
}

void LiveDataUpdate(object o)
{
LiveDataMessage liveDataMessage = new LiveDataMessage()
{
Description = "Live Data at " + DateTime.Now.ToLongTimeString(),
Value = new Random().Next(0, 100)
};
PushToAllClients(liveDataMessage);
}
}

LiveDataService.svc

<%@ ServiceHost
Language="C#"
Debug="true"
Service="DuplexExample.Web.LiveDataService"
%>

6. Config the Duplex Service

The Web.config file looks like below.


<!-- Create the polling duplex binding. -->


receiveTimeout="00:04:00"
inactivityTimeout="00:03:00"
>


receiveTimeout="00:04:00"
inactivityTimeout="00:03:00"
>







behaviorConfiguration="DuplexService.OrderServiceBehavior">
<!-- Specify the service endpoints. -->
binding="pollingDuplexHttpBinding"
behaviorConfiguration="devleapBehavior"
bindingConfiguration="duplexHttpBinding"
contract="Microsoft.Silverlight.Cdf.Samples.Duplex.IUniversalDuplexContract">

binding="pollingDuplexHttpBinding"
behaviorConfiguration="devleapBehavior"
bindingConfiguration="duplexHttpsBinding"
contract="Microsoft.Silverlight.Cdf.Samples.Duplex.IUniversalDuplexContract">

binding="mexHttpsBinding"
contract="IMetadataExchange"/>












7. Create a Silverlight Client Application

The core code to create DuplexServiceClient looks like below.

DuplexServiceClient receiver;
ObservableCollection liveDataMessages = new ObservableCollection();

string address = "http://localhost/DuplexService/LiveDataService.svc";
EndpointAddress endpoint = new EndpointAddress(address);
PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding();
receiver = new DuplexServiceClient(binding,endpoint);

receiver.SendToClientReceived += (sender, e) =>
{
if (e.msg is LiveDataMessage)
{
LiveDataMessage msg = (LiveDataMessage)e.msg;
liveDataMessages.Add(string.Format("{0}. Value = {1}", msg.Description, msg.Value));
}
};

Of course it is required to add reference to the LiveDataService.svc we created earlier.

8. Build and Run the Application

Before the application can build and run, we must add reference to System.ServiceModel.PollingDuplex in both the web site hosting the duplex service and the silverlight project. There are 2 DLL file for service side and Silverlight side, they locate in:

%ProgramFiles%Microsoft SDKsSilverlightv3.0LibrariesServer (this is the one for service)

%ProgramFiles%Microsoft SDKsSilverlightv3.0LibrariesClient (this is the one for Silverlight)

Now build and run the application, and watch the result shown as below.

Push Data From Server to Silverlight Clients With a WCF Duplex Service

9. Step Forward

Now we have an executable sample application built on WCF duplex service and Silverlight3.

I did not apply security future on this application. You can refer to my other blogs to get knowledge about WCF service security.

Download Source Code

[@more@]

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

合阳县| 新乐市| 扎赉特旗| 彝良县| 金平| 石渠县| 施甸县| 赤水市| 白朗县| 黔江区| 上高县| 拉孜县| 罗田县| 井研县| 山西省| 罗定市| 石嘴山市| 舞阳县| 旅游| 无为县| 德保县| 工布江达县| 开远市| 北辰区| 尼勒克县| 鸡西市| 锡林浩特市| 绥宁县| 六盘水市| 松潘县| 新蔡县| 固阳县| 台南县| 鄂温| 沙坪坝区| 象州县| 龙岩市| 长白| 原阳县| 定南县| 中西区|