用Winform客户端测试服务端回调方法,运行到回调方法时客户端无响应(在等待服务端回复消息),直至出现连接超时错误信息。
发送到 http://192.168.0.5:8080/User.svc 的请求操作在配置的超时(00:00:59.9843750)内未收到回复。分配给此操作的时间可能已经是更长超时的一部分。这可能由于服务仍在处理操作或服务无法发送回复消息。请考虑增加操作超时(将通道/代理转换为 IContextChannel 并设置 OperationTimeout 属性)并确保服务能够连接到客户端。
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">服务端代码如下:</span>
服务接口:
namespace WcfService
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IUser”。
[ServiceContract(CallbackContract=typeof(IUserCallback))]
public interface IUser
{
[OperationContract]
string ShowName(string name);
}
public interface IUserCallback
{
[OperationContract(IsOneWay=true)]
void PrintSomething(string str);
}
}
namespace WcfService
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“User”。
public class User : IUser
{
IUserCallback callback = null;
public User()
{
callback = OperationContext.Current.GetCallbackChannel<IUserCallback>();
}
public string ShowName(string name)
{
string str = "服务器回调客户端方法";
callback.PrintSomething(str);
string wcfName = string.Format("WCF服务,显示姓名:{0}", name);
return wcfName;
}
}
}
namespace WCFClient
{
public partial class Form1 : Form
{
UserClient user;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
InstanceContext instanceContext = new InstanceContext(new CallbackHandler(this));
user = new UserClient(instanceContext);
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.AppendText(DateTime.Now.ToString());
string msg = user.ShowName("quan");
textBox1.AppendText("\n");
textBox1.AppendText(msg);
textBox1.AppendText("\n");
textBox1.AppendText(DateTime.Now.ToString());
textBox1.AppendText("\n");
}
public class CallbackHandler : IUserCallback
{
Form1 fm = null;
public CallbackHandler(Form1 fm)
{
this.fm = fm;
}
public void PrintSomething(string str)
{
fm.label1.Text = str+DateTime.Now.ToString();
}
}
}
}
出现以上的客户端超时问题后,检查回调函数,发现问题
将服务端方法中的这行callback.PrintSomething(str);从应答模式的服务方法调用中,移到单独单向方法中调用,系统就回调正常了。
改正后的服务端代码:
服务接口:
namespace WcfService
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IUser”。
[ServiceContract(CallbackContract=typeof(IUserCallback))]
public interface IUser
{
[OperationContract]
string ShowName(string name);
[OperationContract(IsOneWay=true)]
void SetName(string name);
}
public interface IUserCallback
{
[OperationContract(IsOneWay=true)]
void PrintSomething(string str);
}
}
服务实现:
namespace WcfService
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“User”。
public class User : IUser
{
IUserCallback callback = null;
public User()
{
callback = OperationContext.Current.GetCallbackChannel<IUserCallback>();
}
public string ShowName(string name)
{
//string str = "服务器回调客户端方法";
//callback.PrintSomething(str);
string wcfName = string.Format("WCF服务,显示姓名:{0}", name);
return wcfName;
}
public void SetName(string name)
{
callback.PrintSomething(name);
}
}
}
客户端代码:
private void button1_Click(object sender, EventArgs e)
{
textBox1.AppendText(DateTime.Now.ToString());
string msg = user.ShowName("quan");
user.SetName("quan");
textBox1.AppendText("\n");
textBox1.AppendText(msg);
textBox1.AppendText("\n");
textBox1.AppendText(DateTime.Now.ToString());
textBox1.AppendText("\n");
}
程序运行后结果:
综上所述,是因为双工模式下,单向与应答方法混合使用不当的问题。