介紹
WCF(Windows Communication Foundation) - 並發(Concurrent):
1、ConcurrencyMode.Single:單線程並發模式。系統自動加鎖,無並發問題
·InstanceContextMode.PerCall:每個線程都會被分配一個新的實例
·InstanceContextMode.PerSession:每個Session被分配一個新的實例,每個Session內同時只會有一個線程操作實例
·InstanceContextMode.Single:唯一實例,並發調用只會有一個線程操作實例
2、ConcurrencyMode.Reentrant:可重入的單線程並發模式。有可重入(回調)操作時,此模式才會生效,從回調返回的線程會進入隊列尾部排隊
·InstanceContextMode.PerCall:每個線程都會被分配一個新的實例,當有回調操作時如果使用Single並發模式的話就會產生死鎖(1、調用服務端;2、回調客戶端;3、返回服務端,1的時候鎖定了,到3的時候就無法執行了,所以死鎖了),此時應該用Reentrant並發模式
·InstanceContextMode.PerSession:每個Session被分配一個新的實例,每個Session內同時只會有一個線程操作實例,Session內可重入
·InstanceContextMode.Single:唯一實例,並發調用只會有一個線程操作實例,全局可重入
3、ConcurrencyMode.Multiple:多線程並發模式。系統不會自動加鎖,有並發問題
·InstanceContextMode.PerCall:每個線程都會被分配一個新的實例,無並發問題
·InstanceContextMode.PerSession:每個Session被分配一個新的實例,每個Session內多線程操作實例的話會有並發問題
·InstanceContextMode.Single:唯一實例,允許多線程並發操作實例,有並發問題
WCF(Windows Communication Foundation) - 限流(Throttle):
<behaviors> <serviceBehaviors> <behavior name="BehaviorPerCall"> <!--httpGetEnabled - 指示是否發布服務元數據以便使用 HTTP/GET 請求進行檢索,如果發布 WSDL,則為 true,否則為 false,默認值為 false--> <serviceMetadata httpGetEnabled="true"/> <!--maxConcurrentCalls - 服務中同時存在的最大活動消息數,默認值為 16--> <!--maxConcurrentInstances - 服務中同時存在的最大服務實例數,默認值為 Int32.MaxValue--> <!--maxConcurrentSessions - 服務中同時存在的最大會話數,默認值為 10--> <serviceThrottling maxConcurrentCalls="" maxConcurrentInstances="" maxConcurrentSessions="" /> </behavior> <behavior name="BehaviorPerSession"> <serviceMetadata httpGetEnabled="true"/> <serviceThrottling maxConcurrentCalls="" maxConcurrentInstances="" maxConcurrentSessions="" /> </behavior> <behavior name="BehaviorSingle"> <serviceMetadata httpGetEnabled="true"/> <serviceThrottling maxConcurrentCalls="" maxConcurrentInstances="1" maxConcurrentSessions="" /> </behavior> </serviceBehaviors> </behaviors>
示例(以ConcurrencyMode.Reentrant為例)
1、服務
IDuplexReentrant.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCF.ServiceLib.Message
{
/**//// <summary>
/// IDuplexReentrant接口(演示ConcurrencyMode.Reentrant)
/// </summary>
/// <remarks>
/// IDuplexReentrantCallback - 回調接口
/// </remarks>
[ServiceContract(CallbackContract = typeof(IDuplexReentrantCallback))]
public interface IDuplexReentrant
{
/**//// <summary>
/// Hello
/// </summary>
/// <param name="name">名字</param>
[OperationContract]
void HelloDuplexReentrant(string name);
}
/**//// <summary>
/// IDuplexReentrant回調接口
/// </summary>
public interface IDuplexReentrantCallback
{
/**//// <summary>
/// Hello
/// </summary>
/// <param name="name"></param>
[OperationContract]
void HelloDuplexReentrantCallback(string name);
}
}
DuplexReentrant.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCF.ServiceLib.Message
{
/**//// <summary>
/// DuplexReentrant類 (演示ConcurrencyMode.Reentrant)
/// </summary>
/// <remarks>
/// ConcurrencyMode - 獲取或設置一個值,該值指示服務是支持單線程、多線程還是支持可重入調用。默認值為 System.ServiceModel.ConcurrencyMode.Single。
/// Single - 服務實例是單線程的,且不接受可重入調用。
/// Reentrant - 服務實例是單線程的,且接受可重入調用。
/// Multiple - 服務實例是多線程的。
/// </remarks>
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class DuplexReentrant : IDuplexReentrant
{
/**//// <summary>
/// Hello
/// </summary>
/// <param name="name">名字</param>
public void HelloDuplexReentrant(string name)
{
// 聲明回調接口
IDuplexReentrantCallback callback = OperationContext.Current.GetCallbackChannel<IDuplexReentrantCallback>();
// 調用回調接口中的方法
callback.HelloDuplexReentrantCallback(name);
}
}
}
2、宿主
DuplexReentrant.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCF.ServiceHost2.Message
{
/**//// <summary>
/// host WCF.ServiceLib.Message.DuplexReentrant的類
/// </summary>
public class DuplexReentrant
{
/**//// <summary>
/// 啟動WCF.ServiceLib.Message.DuplexReentrant服務
/// </summary>
public void Launch()
{
using (ServiceHost host = new ServiceHost(typeof(WCF.ServiceLib.Message.DuplexReentrant)))
{
host.Open();
Console.WriteLine("服務已啟動(WCF.ServiceLib.Message.DuplexReentrant)");
Console.WriteLine("按<ENTER>停止服務");
Console.ReadLine();
}
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <!--name - 提供服務的類名--> <!--behaviorConfiguration - 指定相關的行為配置--> <service name="WCF.ServiceLib.Message.DuplexReentrant" behaviorConfiguration="MessageBehavior"> <!--address - 服務地址--> <!--binding - 通信方式--> <!--contract - 服務契約--> <endpoint address="Message/DuplexReentrant" binding="netTcpBinding" contract="WCF.ServiceLib.Message.IDuplexReentrant" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:12345/Message/DuplexReentrant"/> <add baseAddress="net.tcp://localhost:54321/"/> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior name="MessageBehavior"> <!--httpGetEnabled - 指示是否發布服務元數據以便使用 HTTP/GET 請求進行檢索,如果發布 WSDL,則為 true,否則為 false,默認值為 false--> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
3、客戶端
DuplexReentrant.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Windows.Forms;
namespace Client2.Message
{
/**//// <summary>
/// 演示Message.DuplexReentrant的類
/// </summary>
public class DuplexReentrant
{
/**//// <summary>
/// Hello
/// </summary>
/// <param name="name">名字</param>
public void HelloDulexReentrant(string name)
{
var ct = new Client2.Message.ReentrantCallbackType();
var ctx = new InstanceContext(ct);
var proxy = new MessageSvc.DuplexReentrant.DuplexReentrantClient(ctx);
proxy.HelloDuplexReentrant(name);
}
}
}
ReentrantCallbackType.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Client2.Message
{
/**//// <summary>
/// 實現回調接口
/// </summary>
/// <remarks>
/// CallbackBehavior - 在客戶端應用程序中配置回調服務實現
/// UseSynchronizationContext - 如果對服務的所有調用都必須在 System.Threading.SynchronizationContext 指定的線程上運行,則為 true;否則為false。默認值為 true。
/// </remarks>
[System.ServiceModel.CallbackBehavior(UseSynchronizationContext = false)]
public class ReentrantCallbackType : MessageSvc.DuplexReentrant.IDuplexReentrantCallback
{
/**//// <summary>
/// Hello
/// </summary>
/// <param name="name">名字</param>
public void HelloDuplexReentrantCallback(string name)
{
MessageBox.Show("Hello: " + name);
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <client> <endpoint address="net.tcp://localhost:54321/Message/DuplexReentrant" binding="netTcpBinding" contract="MessageSvc.DuplexReentrant.IDuplexReentrant"> </endpoint> </client> </system.serviceModel> </configuration>
運行結果:
單擊"btnDuplexReentrant"按鈕後彈出提示框,顯示"Hello: webabcd"
OK