重入與回調并發(Reentrant & CallbackConcurrency )
對于雙工通訊來說,服務對客戶端的回調也是通過代理完成的。那么這又涉及到另外一個問題:回調客戶端時,能否讓回調服務也并發執行呢?WCF中定義了CallbackBehaviorAttribute ,可以通過它來設置回調服務的行為。它同樣定義了ConcurrencyMode,可指定回調的并發模式,但它沒有定義回調的實例模式,即InstanceContextMode。本文主要探討服務的并發與回調服務的并發。
目錄:
- 測試重入與回調并發
- 會話對 重入與回調并發
- 設置服務并發的ServiceBehaviorAttribute能用于回調服務嗎?
publicinterface IAdd
{
[OperationContract]
void Add(int x, int y);
}
{
[OperationContract]
void ShowResult(int result);
}
{
private readonly int counter;
public AddService()
{
counter++;
Console.ResetColor();
Console.WriteLine(string.Format("AddService Construction function excute... counter is {0}", counter));
}
#region IAdd 成員
public void Add(int x, int y)
{
var clientId = OperationContext.Current.IncomingMessageHeaders.GetHeader<int>(MessageWrapper.headerClientId,
MessageWrapper.headerNamespace);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(string.Format("Time:{0};ThreadId is :{1}.Request Id is {2} Add Method Invoked,", DateTime.Now,
Thread.CurrentThread.ManagedThreadId, clientId));
Thread.Sleep(5000);
int result = x + y;
MessageHeader<int> header = new MessageHeader<int>(clientId);
System.ServiceModel.Channels.MessageHeader messageHeader =
header.GetUntypedHeader(MessageWrapper.headerClientId,
MessageWrapper.headerNamespace);
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
Console.WriteLine(string.Format("Time: {1} Requst Id {0} begin Callback",clientId,DateTime.Now));
IAddCallback callbackProxy= OperationContext.Current.GetCallbackChannel<IAddCallback>();
callbackProxy.ShowResult(result);
Console.WriteLine(string.Format("Time: {1} Requst Id {0} Callback finished", clientId, DateTime.Now));
Console.WriteLine(string.Format("result is : {0}",result));
Thread.Sleep(5000);
Console.WriteLine("=========Excute finished=========");
Console.WriteLine();
}
#endregion
}
<services>
<service name="Service.AddService">
<endpoint address="http://127.0.0.1:3636/AddService" binding="wsDualHttpBinding" contract="Contract.IAdd" ></endpoint>
</service>
</services>
</system.serviceModel>
{
private readonly int counter;
public AddCallback()
{
counter++;
Console.WriteLine(string.Format("AddCallback Construction function excute... counter is {0}", counter));
}
#region IAddCallback 成員
public void ShowResult(int result)
{
int callbackRequestId= OperationContext.Current.IncomingMessageHeaders.GetHeader<int>(MessageWrapper.headerClientId,
MessageWrapper.headerNamespace);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(string.Format("Time: {1} ThreadId is :{2} Callback RequestId : {0} 開始執行回調", callbackRequestId, DateTime.Now,Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(10000);
Console.WriteLine(string.Format("Add result is {0}", result));
Console.WriteLine(string.Format("Time: {1} ThreadId is :{2} Callback RequestId : {0} 回調結束", callbackRequestId, DateTime.Now, Thread.CurrentThread.ManagedThreadId));
Console.WriteLine("==================");
Console.WriteLine();
}
#endregion
}
{
InstanceContext instanceContext=new InstanceContext(new AddCallback());
DuplexChannelFactory<IAdd> factory = new DuplexChannelFactory<IAdd>(instanceContext,"AddService");
for (int i = 0; i < 2; i++)
{
IAdd proxy = factory.CreateChannel();
ThreadPool.QueueUserWorkItem(delegate
{
int clientId = Interlocked.Increment(ref index);
using (
OperationContextScope contextScope =
new OperationContextScope(proxy as IContextChannel))
{
MessageHeader<int> header = new MessageHeader<int>(clientId);
System.ServiceModel.Channels.MessageHeader messageHeader =
header.GetUntypedHeader(MessageWrapper.headerClientId,
MessageWrapper.headerNamespace);
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
proxy.Add(1, 2);
}
});
}
}
<wsDualHttpBinding>
<bind name="wsDuplexBinding">
<clientBaseAddress address="http://127.0.0.1:6300/addCallbackService">
<bind>
<wsDualHttpBinding>
</bindings>
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.Single
測試2:
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.Single
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession

服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerCall
服務端輸出:

服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.Single
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
客戶端輸出:
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
客戶端輸出:
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession

服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
客戶端:ConcurrencyMode = ConcurrencyMode.Single

ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession

ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerSession
客戶端輸出:

ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerCall
客戶端輸出:

ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.Single
服務端輸出:
客戶端輸出:

服務端:ConcurrencyMode = ConcurrencyMode.Reentrant,InstanceContextMode = InstanceContextMode.PerCall
客戶端:ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,InstanceContextMode = InstanceContextMode.PerCall)
服務端輸出:
客戶端輸出:

由測試10、11、12、18這些測試得出如下結論:ServiceBehaviorAttribute對回調服務的并發設置無效。
會話模式下,不同客戶端代理對可重入的服務總是以并發的方式執行;相同客戶端對可重入的服務總是以串行的方式執行,而無論怎樣,回調服務總是以串行的方式執行。
浙公網安備 33010602011771號