【问题标题】:WCF service is not multithreadedWCF 服务不是多线程的
【发布时间】:2014-04-01 08:44:03
【问题描述】:

我正在设计 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>

问题是,每个请求都在同一个线程上处理。 我在网上查了很多,但对我来说一切都很好......

你们有什么想法吗?

谢谢!

【问题讨论】:

  • 你是怎么检查的?如果有 50 个客户端执行该服务并且您将其置于睡眠状态,它们是否会一个接一个地等待处理?
  • 多少个请求,在什么时间段内,持续多长时间?
  • 我咨询了两个客户。首先,可以清楚地看到来自客户端 #2 的请求 #1 正在等待来自客户端 #1 的第一个请求,以及一些 Console.Write(ManagedThreadId)
  • 到目前为止,来自 2 个客户端的 20 个请求,每个请求 5 秒
  • 如何托管此 WCF 服务(IIS、Windows 服务等)?

标签: c# multithreading web-services wcf


【解决方案1】:

打开ServiceHost 时,WCF 会捕获当前的SynchronizationContext,并将其用于所有调用。 WPF 的同步上下文将每次调用都发布到 Dispatcher 队列,最终在 UI 线程上执行。

你有两个选择:

  • 在没有同步上下文的不同线程上启动服务。这具有不阻塞等待服务加载的 UI 线程的额外优点。例如,您可以使用:

    Task.Run(() => serviceHost.Open());
    
  • 指定服务不应使用同步上下文:

    [ServiceBehavior(UseSynchronizationContext = false)]
    

请注意,如果您在服务方法中修改 UI 对象,您可能需要自己将它们分派回 UI 线程。

【讨论】:

  • 太棒了!一行代码,现在一切都很顺利:D 非常感谢!
【解决方案2】:

如果您希望您的服务在来自同一客户端的调用之间保持某种状态,那么值得一提的是InstanceContextMode=InstanceContextMode.PerSession。否则,您可以使用InstanceContextMode=InstanceContextMode.PerCall

【讨论】:

  • 我确实需要会话,我正在使用来自服务的大量推送请求
  • 我不确定模拟 50 个客户呼叫时所需的验证级别。但是,ServiceThrottling 可能是最好的起点。你也可以看看这篇文章codeproject.com/Articles/33362/WCF-Throttling
  • 我认为关于 ServiceThrottling 的配置还可以,不是吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 2016-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多