WCF服务不支持多线程。

4

我将为一款WPF应用程序设计一个WCF服务。

该服务将被50个客户端使用,并托管于多核服务器上。因此,我希望它是多线程的。

以下是我声明它的方式:

[ServiceContract(
    SessionMode = SessionMode.Required,
    Namespace = Constants.NameSpace,
    CallbackContract = typeof (ISaphirServiceCallback))]
public interface ISaphirService


[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, 
                InstanceContextMode=InstanceContextMode.PerSession)]
public partial class SaphirService : ISaphirService

服务器端配置:

  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="NewBinding0" receiveTimeout="00:59:00" sendTimeout="00:59:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="20000000">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <reliableSession ordered="true" inactivityTimeout="00:30:00" enabled="true"/>
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </netTcpBinding>

      <customBinding>
        <binding name="ServicePECB2ServiceBinding">
          <textMessageEncoding messageVersion="Soap12WSAddressing10" />
          <httpsTransport />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="https://qualiflps.services-ps.ameli.fr/lps" binding="customBinding" bindingConfiguration="ServicePECB2ServiceBinding" contract="ServiceReference1.ServicePECB2Service" name="ServicePECB2Service" />
    </client>

    <behaviors>
      <serviceBehaviors>
        <behavior name="NewBehavior0">
          <serviceThrottling maxConcurrentCalls="50" maxConcurrentSessions="50" maxConcurrentInstances="50"/>
          <serviceAuthorization serviceAuthorizationManagerType="Service.Authorizations.AuthorizationPolicy, Service">
            <authorizationPolicies>
              <add policyType="Service.Authorizations.AuthorizationPolicy, Service" />
            </authorizationPolicies>
          </serviceAuthorization>
          <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:80/Service" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <serviceCertificate storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName" findValue="*****" />
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Service.Authorizations.CustomValidator, Service" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="NewBehavior0" name="Service.Services.SaphirService">
        <endpoint address="basic" binding="netTcpBinding" bindingConfiguration="NewBinding0" contract="ServiceInterfaces.IServices.ISaphirService">
          <identity>
            <dns value="*****" />
          </identity>
        </endpoint>
      </service>
    </services>
  </system.serviceModel>

以下是客户端配置:

  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="NetTcpBinding_ISaphirService" receiveTimeout="00:30:00" sendTimeout="00:05:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="20000000">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <reliableSession ordered="true" inactivityTimeout="00:30:00" enabled="true"/>
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="http://****:4224/service/basic" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ISaphirService" contract="ISaphirService" name="NetTcpBinding_ISaphirService" behaviorConfiguration="CustomBehavior">
        <identity>
          <certificate encodedValue="****" />
        </identity>
      </endpoint>
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CustomBehavior">
          <clientCredentials>
            <serviceCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

问题在于,每个请求都在同一个线程上处理。

我在网上查了很多资料,但一切看起来似乎都很好...

你们有什么想法吗?

谢谢!


3
你是如何进行检查的?如果有50个客户端执行该服务,并且你在其中加入了延迟,它们会一个接一个地等待处理吗? - nvoigt
2
在多长时间内有多少个请求,以及每个请求的持续时间是多少? - Andrew Barber
我与两个客户进行了核实。首先可以清楚地看到,来自客户端#2的请求#1正在等待来自客户端#1的第一个请求,并且还使用了一些Console.Write( ManagedThreadId )。 - Guillaume Philipp
到目前为止,来自2个客户的20个请求,每个请求需要5秒钟。 - Guillaume Philipp
这个WCF服务是如何托管的(IIS,Windows Service等)? - noseratio - open to work
在 WPF 应用程序中,有些奇怪的事情:在长时间查询期间 UI 会冻结。WCF 不是应该为每个请求创建线程吗? - Guillaume Philipp
2个回答

7
打开一个WCF的ServiceHost时,WCF会捕获当前的SynchronizationContext并将其用于所有调用。WPF的同步上下文将每个调用都发布到Dispatcher队列中,最终在UI线程上执行。
你有两个选择:
  • Start the service on a different thread that doesn't have a synchronization context. This has the additional advantage of not blocking the UI thread waiting for the service to load. For example, you can use:

    Task.Run(() => serviceHost.Open());
    
  • Specify that the service should not use the synchronization context:

    [ServiceBehavior(UseSynchronizationContext = false)]
    
请注意,如果您在服务方法中修改UI对象,则可能需要自己将它们调度回UI线程。

太棒了!只用一行代码,现在一切都顺畅了:D 非常感谢你! - Guillaume Philipp

0
如果您希望您的服务在同一客户端的多次调用之间保持某些状态,则值得提到InstanceContextMode=InstanceContextMode.PerSession。否则,您可以使用InstanceContextMode=InstanceContextMode.PerCall

我确实需要会话,因为我正在从服务中使用大量的推送请求。 - Guillaume Philipp
我不确定模拟50个客户端调用时需要多少级别的验证。然而,ServiceThrottling可能是最好的起点。您还可以查看这篇文章http://www.codeproject.com/Articles/33362/WCF-Throttling。 - S.N
我认为我的ServiceThrottling配置是正确的,不是吗? - Guillaume Philipp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接