I'm designing a WCF service used by a WPF application. The service will be used by 50 clients and hosted on a multi core server. That's why I would like it to be multi threaded.
This is how I declared it :
[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
And the server side configuration :
<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>
And here is the client side configuration :
<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>
The thing is, each request are processed on the same Thread. I checked a lot on the Internet but everything seems good to me...
Do you guys have any idea ?
Thanks !
When opening a ServiceHost
WCF captures the current SynchronizationContext
, and uses it for all calls. WPF's synchronization context posts every call to the Dispatcher
queue, which ends up executing on the UI thread.
You have two options:
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)]
Note that if you modify UI objects in service methods, you might need to dispatch them back to the UI thread yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With