このサンプル コードでは、クライアントが ECF サーバーで関数を呼び出し、サーバーもクライアント関数を呼び出します。
次のサンプルでは、イベント サブスクリプションも確認できます。
サンプル コード SampleServiceClient :
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
using SampleServiceClient.SampleServiceReference;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;
namespace SampleServiceClient
{
/*WCF duplex use a SynchronizationContext by default, which means the callback will happen on UI threadm,
* so that you can update UI in your callback. But your client are calling your server in on the UI thread,
* so the callback will never be able to be delivered to your client. that's the orignal reason why it blocked.
*
Now if you use Synchronization=false, the callback will be delivered to you by a non-UI thread,
* that's why you can receive the callback now.
* After you receive the callback, you still want to update the UI in the UI thread,
* but the UI thread is still blocking now waiting for server response, so that's why it is blocking again, is it right?*/
[CallbackBehavior(UseSynchronizationContext = false)]
class SampleCallback : IService1Callback
{
frmClient frm;
public SampleCallback()
{
}
public SampleCallback(frmClient Form1)
{
frm = Form1;
}
public void ShowCallbackMessage(string message)
{
SetText("Callback message --> " + message);
}
public void OnPriceChanged(int value)
{
SetText("On Price Changed by client number : " + value.ToString());
}
private void SetText(String str)
{
SendOrPostCallback instance = new SendOrPostCallback(frm.AddItem);
frm.BeginInvoke(instance, str);
}
}
}
サーバー側のコード:
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
namespace SampleService
{
//No Service Contract Tag for Callback Inteface
interface ISampleCallback
{
[OperationContract(IsOneWay = true)]
void ShowCallbackMessage(string message);
[OperationContract(IsOneWay = true)]
void OnPriceChanged(int value);
}
//Name of Callback Contract on the WCF Service Contract which we want to expose to client
//You can assosiate only one CallBack Interface with a WCF Service Contract
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ISampleCallback))]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract (IsOneWay=true)]
void ChangePrice(int value);
//Code to Show Events Programming
[OperationContract]
bool SubscribeToPriceChangedEvent();
[OperationContract]
bool UnsubscribeFromPriceChangedEvent();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class Service1 : IService1
{
static List<ISampleCallback> clients = new List<ISampleCallback>();
private ISampleCallback callback=null;
internal ISampleCallback Callback
{
get { return callback; }
set { callback = value; }
}
public string GetData(int value)
{
//Invoke the callback operation in the client operation
callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
//All WCF channels implements the ICommunicationObject interface.
//If State is not opened then the service should not attempt to use callback.
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
Callback.ShowCallbackMessage("You are the client number " + value.ToString());
}
return string.Format("Callback message sent to client number " + value.ToString());
}
public void ChangePrice(int value)
{
raisePriceChangedEvent(value);
}
//Event Programming
public bool SubscribeToPriceChangedEvent()
{
try
{
Callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
if (!clients.Contains(Callback))
{
clients.Add(Callback);
}
return true;
}
catch (Exception)
{
return false;
}
}
public bool UnsubscribeFromPriceChangedEvent()
{
try
{
Callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
clients.Remove (Callback);
return true;
}
catch (Exception)
{
return false;
}
}
private void raisePriceChangedEvent(int value)
{
clients.ForEach(delegate(ISampleCallback oCallback)
{
if (((ICommunicationObject)oCallback).State == CommunicationState.Opened)
{
oCallback.OnPriceChanged(value);
}
else
{
clients.Remove(oCallback);
}
});
}
}
}