WCF callback机制的应用:实时投票模型
在WCF应用callback模式时,一些指导性的document给出的建议是将callback contract内的operation的Message Exchange Pattern设置为IsOneWay.
当然,当service调用callback而不需要从client instance获得callback的return value的时候,MEP设置为IsOneWay不失为最好的选择了。但是如果在某些应用场景下,我们需要获得客户端callback结果时候,就不能将MEP设置为IsOneWay=true了。
当然,当MEP设置为IsOneWay=false的时候,其他同步设置必须相应match,即ConcurrentMode只能为ReEntrant或者Multiple。
下面给出一个简单的应用模式:在线实时投票。
其简单系统模型如下:
WCF service提供一个简单的投票服务,收集投票结果通过callback机制得到各个client的结果后然后返回给service,然后WCF service给出statistics.
针对这样的投票模型,在设置service的时候需要注意的是:
1.callback contract中的operation一定要设置为IsOneWay=false。否则callback无法return至服务端
2.ConcurrentMode不能设置为Single,而只能为ReEntrant或者Multiple.
3. 当service callbacks client的时候,callback result的处理权在service,比如对结果进行统计处理等等。
下面给出主要的source code:
callback contract和service contract的定义
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCFCallBack
{
[ServiceContract]
public interface ICaculatorCallBack
{
[OperationContract]
int Equals(int result);
}
[ServiceContract(CallbackContract=typeof(ICaculatorCallBack))]
public interface ICaculatorService
{
[OperationContract]
void AddTo(int n);
[OperationContract]
void Register();
}
}
servicecontract implementation以及消息发布
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCFCallBack
{
public class AddEventAgrs : EventArgs
{
public int result;
}
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
class CaculatorService:ICaculatorService
{
public delegate void AddEventHandler(object sender, AddEventAgrs e);
public static event AddEventHandler OnAddCompleted;
public ICaculatorCallBack callback;
public int result;
public CaculatorService()
{
result = 0;
Console.WriteLine("A Calculator Instance is constructed");
}
public void Register()
{
callback = System.ServiceModel.OperationContext.Current.GetCallbackChannel<ICaculatorCallBack>();
OnAddCompleted += new AddEventHandler(CaculatorService_OnAddCompleted);
}
void CaculatorService_OnAddCompleted(object sender, AddEventAgrs e)
{
Console.WriteLine("the OnAdd event has been triggered");
Console.WriteLine("the callback result from client is "+callback.Equals(e.result));
}
public void BroadAddEvent(AddEventAgrs e, AddEventHandler temp)
{
if (OnAddCompleted != null)
{
foreach (AddEventHandler handler in temp.GetInvocationList())
{
handler.BeginInvoke(this, e, null, null);
}
}
}
public void AddTo(int n)
{
AddEventAgrs e = new AddEventAgrs();
this.result += n;
e.result = result;
BroadAddEvent(e, OnAddCompleted);
}
}
}
client1 callback实现:
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WCFClient
{
class CallBack:ICaculatorServiceCallback
{
public int Equals(int n)
{
//Console.WriteLine("haha");
Console.WriteLine("this callback is implemented on client,the callback result is {0}", n.ToString());
return 2*n ;
}
}
}
client2 callback implementation
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WCFClient
{
class CallBack:ICaculatorServiceCallback
{
public int Equals(int n)
{
Console.WriteLine("I have received a broadcasting news,the callback result is {0}", n.ToString());
System.Threading.Thread.Sleep(2000);
return n * n;
}
}
}
运行结果:
service screenshot
client1 screenshot
client 2 screenshot