我开发了一个概念证明应用程序,用于查询WCF是否支持多线程。
现在,我所做的就是创建一个标有
的服务合同 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple,
UseSynchronizationContext = true)]
有两个操作来获取固定文本。
第一种方法执行Thread.Sleep
8秒钟以使响应延迟,另一种方法直接返回数据。
我遇到的问题是当我运行两个客户端应用程序实例并从第一个客户端请求延迟方法并从第二个客户端请求另一个方法时,我得到了顺序响应。
如果服务忙于其他请求,我如何从服务获得响应?
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
}
}
我需要同时调用方法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();
}
}
}
以下是我为测试案例而实施的代码:
服务器端类
服务界面
namespace WCFSessionServer
{
[ServiceContract]
public interface IService
{
[OperationContract]
string GetDelayedResponse();
[OperationContract]
string GetDirectResponse();
}
}
实施班
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
}
}
服务器端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>
客户端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>
答案 0 :(得分:17)
好吧,通过将您的服务定义为
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,
ConcurrencyMode=ConcurrencyMode.Multiple,
UseSynchronizationContext=true)]
您基本上将服务类定义为单例(InstanceContextMode.Single
),这当然不是最好的方法。通过将其定义为ConcurrencyMode.Multiple
,您可以将其设置为多线程单例 - 这会给您带来很多负担,确保您的代码在自己的肩膀上具有200%的线程安全性。
我的建议是按呼叫标记您的服务实现类。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,
ConcurrencyMode=ConcurrencyMode.Single)]
使用这种方法,WCF运行时本身将根据需要启动尽可能多的服务实例类,以处理您的请求。在您的示例中,WCF运行时将创建并启动两个ServiceImplementation
实例,每个请求一个,并同时处理这些调用。最大的优点是:由于每个服务实例类只提供一个请求,因此您无需担心代码中的并发管理 - 您在“单线程”类中,并且WCF运行时处理与之相关的所有问题有多个请求并妥善处理它们。
更新:您仍然不显示您是如何创建客户端服务代理的,以及您如何调用您的服务。您已经发布了所有服务器端代码 - 但不是一堆客户端代码。
好的,这是怎么做的:
Client1
和Client2
Add Service Reference
向服务添加服务引用将在“服务参考”地球
您现在需要在两个客户端项目中实例化客户端代理的实例:
In Client1:
var instance1 = new ServiceImplementationClient();
In Client2:
var instance2 = new ServiceImplementationClient();
Client1
会调用您的第一个方法GetDelayedResponse
,而Client2
会调用GetDirectResponse
:
In Client1:
instance1.GetDelayedResponse();
In Client2:
instance2.GetDirectResponse();
如果您同时运行这两个应用,您应该会看到Client2
立即返回,而Client1
将等待那8秒。
如果你有两个完全独立的客户端,并且他们将在服务器上获得一个完全独立的服务实例,它们完全独立,并且不会序列化他们的呼叫,也不会相互阻塞。
答案 1 :(得分:0)
尝试更改属性的值
UseSynchronizationContext=false