WCF是否支持多线程?

Sab*_*ith 11 wcf

我开发了一个概念验证应用程序,用于查询WCF是否支持多线程.

现在,我所做的就是创建一个标有的服务合同

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
                  ConcurrencyMode = ConcurrencyMode.Multiple, 
                  UseSynchronizationContext = true)]
Run Code Online (Sandbox Code Playgroud)

有两个操作来获取固定文本.第一种方法执行a Thread.Sleep8秒钟以使响应延迟,另一种方法直接返回数据.

我遇到的问题是当我运行两个客户端应用程序实例并从第一个客户端请求延迟方法并从第二个客户端请求另一个方法时,我得到了一个顺序响应.

当服务忙于另一个请求时,如何从服务获得响应?

 namespace WCFSyncService
 {
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)], 
                 ConcurrencyMode = ConcurrencyMode.Multiple, 
                 UseSynchronizationContext = true)]

    public class ServiceImplementation : IService

    {
        public ServiceImplementation()
        {
        }

        #region IService Members

        public string GetDelayedResponse()
        {
            System.Threading.Thread.Sleep(8000);
            return "Slow";
        }

        public string GetDirectResponse()
        {
            return "Fast";
        }

        #endregion
    }
}
Run Code Online (Sandbox Code Playgroud)

我需要调用方法GetDelayedResponse,GetDirectResponse同时在8秒结束前获得"快速"文本.


托管应用程序代码

namespace ServiceHostApplication
{
    public partial class frmMain : Form
    {
        private WCFSessionServer.IService oService;

        public frmMain()
        {
            InitializeComponent();
        }

        private void btnStartService_Click(object sender, EventArgs e)
        {
            ServiceHost objSvcHost;

            oService = new WCFSessionServer.ServiceImplementation();
         objSvcHost = new ServiceHost( typeof(WCFSessionServer.ServiceImplementation));
            objSvcHost.Open();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

下面是我实现它来测试案例的代码:

服务器端类,

  1. 服务的界面

    namespace WCFSessionServer
    {
        [ServiceContract]
        public interface IService
    
        {
            [OperationContract]
            string GetDelayedResponse();
    
           [OperationContract]
           string GetDirectResponse();
        }
     }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 实施课

    namespace WCFSessionServer
    {
       [ServiceBehavior(
                        InstanceContextMode = InstanceContextMode.PerCall,
                        ConcurrencyMode =   ConcurrencyMode.Multiple,
                        UseSynchronizationContext =  true)]
        public class ServiceImplementation : IService
         {
             public ServiceImplementation()
                {
                }
    
             #region Service Members
             public string GetDelayedResponse()
                {
                 System.Threading.Thread.Sleep(8000);
                 return "Slow";
                }
    
             public string GetDirectResponse()
             {
                 return "Fast";
             }
             #endregion
         }
     }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 服务器端app.config

    <system.serviceModel>
     <services>
      <service 
                behaviorConfiguration = "WCFSessionServer.IService"  
                name = "WCFSessionServer.ServiceImplementation" >
      <endpoint address="http://localhost:2020/SessionService/basic/"
                behaviorConfiguration="WCFSessionServer.IService"
                binding="basicHttpBinding"
                name="BasicHttpBinding_IService"
                bindingName="myBasicHttpBinding"
                contract="WCFSessionServer.IService" />
      <endpoint address="mex"
                binding="mexHttpBinding"
                contract="IMetadataExchange" />
      <host>
       <baseAddresses>
         <add baseAddress="http://localhost:2020/SessionService/" />
       </baseAddresses>
      </host>
    </service>
     </services>
          <behaviors>
          <endpointBehaviors>
           <behavior name="TimeOut">
            <callbackTimeouts transactionTimeout="00:00:02"/>
          </behavior>
         <behavior name="WCFSessionServer.IService" >
           <dataContractSerializer maxItemsInObjectGraph="2147483647" />
         </behavior>
       </endpointBehaviors>
       <serviceBehaviors>
        <behavior name="WCFSessionServer.IService">
           <serviceThrottling    maxConcurrentCalls="10"
                                 maxConcurrentSessions="10"
                                 maxConcurrentInstances="10"/>
               <dataContractSerializer maxItemsInObjectGraph="2147483647" />
               <serviceMetadata httpGetEnabled="True"/> 
               <serviceDebug includeExceptionDetailInFaults="True" />
             </behavior>
           </serviceBehaviors>
         </behaviors>
       </system.serviceModel>
    
    Run Code Online (Sandbox Code Playgroud)

客户端app.config

    <system.serviceModel>
          <bindings>
              <basicHttpBinding>
                  <binding name="BasicHttpBinding_IService"
                           closeTimeout="00:01:00"
                           openTimeout="00:01:00"
                           receiveTimeout="00:10:00"
                           sendTimeout="00:01:00"
                           allowCookies="false"
                           bypassProxyOnLocal="false"
                           hostNameComparisonMode="StrongWildcard"
                           maxBufferSize="65536"
                           maxBufferPoolSize="524288"
                           maxReceivedMessageSize="65536"
                           messageEncoding="Text"
                           textEncoding="utf-8"
                           transferMode="Buffered"
                           useDefaultWebProxy="true">
                           <readerQuotas maxDepth="32"
                                         maxStringContentLength="8192"
                                         maxArrayLength="16384"
                                         maxBytesPerRead="4096"
                                         maxNameTableCharCount="16384" />
                    <security mode="None">
                    <transport
                              clientCredentialType="None"
                              proxyCredentialType="None"
                              realm="" />
                    <message 
                             clientCredentialType="UserName"
                             algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:2020/SessionService/basic/"
                  binding="basicHttpBinding"
                  bindingConfiguration="BasicHttpBinding_IService"
                  contract="SessionServiceProxy.IService"
                  name="BasicHttpBinding_IService" />
    </client>
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)

mar*_*c_s 17

好吧,通过定义您的服务

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, 
                 ConcurrencyMode=ConcurrencyMode.Multiple, 
                 UseSynchronizationContext=true)] 
Run Code Online (Sandbox Code Playgroud)

你基本上将你的服务类定义为singleton(InstanceContextMode.Single),这当然不是最好的方法.通过将其定义为ConcurrencyMode.Multiple,您可以将其设置为多线程单例 - 这会给您带来很多负担,确保您的代码在您自己的肩膀上具有200%的线程安全性.

我的建议是按呼叫标记您的服务实现类.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall, 
                 ConcurrencyMode=ConcurrencyMode.Single)] 
Run Code Online (Sandbox Code Playgroud)

使用此方法,WCF运行时本身将根据需要启动尽可能多的服务实例类,以处理您的请求.在您的示例中,WCF运行时将创建并启动两个实例ServiceImplementation,每个请求一个,并同时处理调用.最大的优点是:由于每个服务实例类只提供一个请求,因此您无需担心代码中的并发管理 - 您在"单线程"类中,并且WCF运行时处理与之相关的所有问题有多个请求并适当地处理它们.

更新:您仍然没有显示您是如何创建客户端服务代理的,以及您如何调用您的服务.您已经发布了所有服务器端代码 - 但不是一堆客户端代码.

好的,这是怎么做的:

  • 启动服务主机并确保它正在运行
  • 在Visual Studio中创建两个单独的控制台应用程序项目,为您的客户-给他们打电话Client1Client2
  • 在这两个新客户端项目中,用于Add Service Reference向服务添加服务引用
  • 这将在"服务参考"地球仪下创建一堆文件

  • 您现在需要在两个客户端项目中实例化客户端代理的实例:

     In Client1:
         var instance1 = new ServiceImplementationClient();
    
     In Client2:
         var instance2 = new ServiceImplementationClient();
    
    Run Code Online (Sandbox Code Playgroud)
  • Client1将调用您的第一个方法GetDelayedResponse,同时Client2将调用GetDirectResponse:

     In Client1:
         instance1.GetDelayedResponse();
    
     In Client2:
         instance2.GetDirectResponse();
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果你同时运行这两个应用程序,你应该看到立即Client2返回,而Client1等待那8秒.

如果你有两个完全独立的客户端,并且他们将在服务器上获得一个完全独立的服务实例,它们完全独立,并且不会序列化他们的呼叫,也不会相互阻塞.