介紹
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