实现双工时 WCF 中的超时异常
TimeOut exception in WCF while implementing duplex
我的服务合同和回调合同如下所示:
[ServiceContract(CallbackContract = typeof(IWebshopCallback))]
interface IWebshop
{
[OperationContract]
string GetWebshopName ();
[OperationContract]
string GetProductInfo (Item i);
[OperationContract]
List<Item> GetProductList ();
[OperationContract]
bool BuyProduct (string i);
[OperationContract]
void ConnectNewClient ();
}
[ServiceContract]
interface IWebshopCallback
{
[OperationContract]
void NewClientConnected (int totalNrOfConnectedClients);
}
我的服务:
[ServiceBehavior (InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
class WebshopService : IWebshop
{
...
}
在服务内部,我有一个方法可以调用客户端的另一个方法:
public void ConnectNewClient ()
{
totalNumber++;
OperationContext.Current.GetCallbackChannel<IWebshopCallback> ().NewClientConnected (totalNumber);
}
在客户端,我有一个派生自 IWebshopCallback 的表单,它有一个方法 NewClientConnected(int a)。
问题是,当我尝试 运行 我的代码时,我 运行 进入了这个异常:
This request operation sent to http://localhost:4000/IWebshopContract did not receive a reply within the configured timeout (00:00:59.9989895). The time allotted to this operation may have been a portion of a longer timeout.
但是,更奇怪的是,如果我继续我的应用程序的工作,我会发现此功能有效。
是什么导致了这一切?
在服务器端调用函数时需要使用 Task.Run(),所以应该这样:
var callback = OperationContext.Current.GetCallbackChannel<IWebshopCallback> ();
Task.Run (() => callback.NewClientConnected(totalNumber));
而不是这样:
OperationContext.Current.GetCallbackChannel<IWebshopCallback> ().NewClientConnected ();
一般情况下,我们除了双工的行为是客户端returns在调用服务后立即,服务器发回的信息通过回调契约传递。在这种工作模式下,我们把服务契约和回调契约都变成了单向通信。
[OperationContract(Action = "post_num", IsOneWay = true)]
void PostNumber(int n);
我做了一个demo,希望对你有用。
服务器端。
class Program
{
static void Main(string[] args)
{
using (ServiceHost sh=new ServiceHost(typeof(MyService)))
{
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb==null)
{
smb = new ServiceMetadataBehavior()
{
HttpGetEnabled = true
};
sh.Description.Behaviors.Add(smb);
}
sh.Open();
Console.WriteLine("Service is ready");
Console.ReadKey();
sh.Close();
}
}
}
[ServiceContract(Namespace ="mydomain",Name = "demo", ConfigurationName = "isv", CallbackContract = typeof(ICallback))]
public interface IDemo
{
[OperationContract(Action = "post_num", IsOneWay = true)]
void PostNumber(int n);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(Action = "report", IsOneWay = true)]
void Report(double progress);
}
[ServiceBehavior(ConfigurationName ="sv")]
public class MyService : IDemo
{
public void PostNumber(int n)
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
for (int i = 0; i <=n; i++)
{
Task.Delay(500).Wait();
double p = Convert.ToDouble(i) / Convert.ToDouble(n);
callback.Report(p);
}
}
}
服务器配置
<system.serviceModel>
<services>
<service name="sv">
<endpoint address="http://localhost:3333" binding="wsDualHttpBinding" contract="isv"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:3333"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
客户端。
class Program
{
static void Main(string[] args)
{
DuplexChannelFactory<IDemo> factory = new DuplexChannelFactory<IDemo>(new CallbackHandler(), "test_ep");
IDemo channel = factory.CreateChannel();
Console.WriteLine("Start to Call");
channel.PostNumber(15);
Console.WriteLine("Calling is done");
Console.ReadLine();
}
}
[ServiceContract(Namespace ="mydomain",Name = "demo", ConfigurationName = "isv", CallbackContract = typeof(ICallback))]
public interface IDemo
{
[OperationContract(Action = "post_num",IsOneWay =true)]
void PostNumber(int n);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(Action = "report",IsOneWay =true)]
void Report(double progress);
}
public class CallbackHandler : ICallback
{
public void Report(double progress)
{
Console.WriteLine("{0:p0}", progress);
}
}
客户端配置
<system.serviceModel>
<client>
<endpoint name="test_ep" address="http://localhost:3333" binding="wsDualHttpBinding" contract="isv"/>
</client>
</system.serviceModel>
结果。
我的服务合同和回调合同如下所示:
[ServiceContract(CallbackContract = typeof(IWebshopCallback))]
interface IWebshop
{
[OperationContract]
string GetWebshopName ();
[OperationContract]
string GetProductInfo (Item i);
[OperationContract]
List<Item> GetProductList ();
[OperationContract]
bool BuyProduct (string i);
[OperationContract]
void ConnectNewClient ();
}
[ServiceContract]
interface IWebshopCallback
{
[OperationContract]
void NewClientConnected (int totalNrOfConnectedClients);
}
我的服务:
[ServiceBehavior (InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
class WebshopService : IWebshop
{
...
}
在服务内部,我有一个方法可以调用客户端的另一个方法:
public void ConnectNewClient ()
{
totalNumber++;
OperationContext.Current.GetCallbackChannel<IWebshopCallback> ().NewClientConnected (totalNumber);
}
在客户端,我有一个派生自 IWebshopCallback 的表单,它有一个方法 NewClientConnected(int a)。
问题是,当我尝试 运行 我的代码时,我 运行 进入了这个异常:
This request operation sent to http://localhost:4000/IWebshopContract did not receive a reply within the configured timeout (00:00:59.9989895). The time allotted to this operation may have been a portion of a longer timeout.
但是,更奇怪的是,如果我继续我的应用程序的工作,我会发现此功能有效。
是什么导致了这一切?
在服务器端调用函数时需要使用 Task.Run(),所以应该这样:
var callback = OperationContext.Current.GetCallbackChannel<IWebshopCallback> ();
Task.Run (() => callback.NewClientConnected(totalNumber));
而不是这样:
OperationContext.Current.GetCallbackChannel<IWebshopCallback> ().NewClientConnected ();
一般情况下,我们除了双工的行为是客户端returns在调用服务后立即,服务器发回的信息通过回调契约传递。在这种工作模式下,我们把服务契约和回调契约都变成了单向通信。
[OperationContract(Action = "post_num", IsOneWay = true)]
void PostNumber(int n);
我做了一个demo,希望对你有用。
服务器端。
class Program
{
static void Main(string[] args)
{
using (ServiceHost sh=new ServiceHost(typeof(MyService)))
{
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb==null)
{
smb = new ServiceMetadataBehavior()
{
HttpGetEnabled = true
};
sh.Description.Behaviors.Add(smb);
}
sh.Open();
Console.WriteLine("Service is ready");
Console.ReadKey();
sh.Close();
}
}
}
[ServiceContract(Namespace ="mydomain",Name = "demo", ConfigurationName = "isv", CallbackContract = typeof(ICallback))]
public interface IDemo
{
[OperationContract(Action = "post_num", IsOneWay = true)]
void PostNumber(int n);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(Action = "report", IsOneWay = true)]
void Report(double progress);
}
[ServiceBehavior(ConfigurationName ="sv")]
public class MyService : IDemo
{
public void PostNumber(int n)
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
for (int i = 0; i <=n; i++)
{
Task.Delay(500).Wait();
double p = Convert.ToDouble(i) / Convert.ToDouble(n);
callback.Report(p);
}
}
}
服务器配置
<system.serviceModel>
<services>
<service name="sv">
<endpoint address="http://localhost:3333" binding="wsDualHttpBinding" contract="isv"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:3333"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
客户端。
class Program
{
static void Main(string[] args)
{
DuplexChannelFactory<IDemo> factory = new DuplexChannelFactory<IDemo>(new CallbackHandler(), "test_ep");
IDemo channel = factory.CreateChannel();
Console.WriteLine("Start to Call");
channel.PostNumber(15);
Console.WriteLine("Calling is done");
Console.ReadLine();
}
}
[ServiceContract(Namespace ="mydomain",Name = "demo", ConfigurationName = "isv", CallbackContract = typeof(ICallback))]
public interface IDemo
{
[OperationContract(Action = "post_num",IsOneWay =true)]
void PostNumber(int n);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(Action = "report",IsOneWay =true)]
void Report(double progress);
}
public class CallbackHandler : ICallback
{
public void Report(double progress)
{
Console.WriteLine("{0:p0}", progress);
}
}
客户端配置
<system.serviceModel>
<client>
<endpoint name="test_ep" address="http://localhost:3333" binding="wsDualHttpBinding" contract="isv"/>
</client>
</system.serviceModel>
结果。