积极答复者
急求双工回调的问题??

问题
-
工作流程:
1.客户端发起gettask请求。
2.服务端从数据库中得到任务后调用回调sendtask把任务送到客户端。
问题:
正常情况下该流程没有问题,但如果我把服务端关掉后再打开(网线拔了再插上也一样),第1步调用没问题,第2步总是报如下错“http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous 的请求操作在配置的超时(00:02:00)内未收到回复。分配给该操作的时间可能是更长超时的一部分。这可能由于服务仍在处理操作或服务无法发送回复消息。请考虑增加操作超时(将通道/代理转换为 IContextChannel 并设置 OperationTimeout 属性)并确保服务能够连接到客户端。”---感觉回调被阻塞一样。
服务端相关代码:
[ServiceContract(CallbackContract = typeof(ITaskCallback), SessionMode = SessionMode.Required)]
public interface ITasksService
{[OperationContract(IsOneWay = true)]
void getTask(Task task);
}
//回调
public interface ITaskCallback
{
[OperationContract]
bool SendTask(Task task);
}[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
// NOTE: If you change the class name "TasksService" here, you must also update the reference to "TasksService" in App.config.
public class TasksService : ITasksService
{
private string IP = "";
public void getTask(Task task)
{
Business.addLog(">>getTask", task.OperID, 2);Business bs = new Business();
task.TaskXml = "";
string taskXML = bs.getTaskXML(ref task);
if (taskXML.Length > 0)
{
bs.saveToRECOperWorkInfo(task.OperID, task.ID, task.SkillID, task.BatchID);
}
Business.addLog("<<getTask", task.OperID, 2);try
{
if (callback.SendTask(task))
Business.addLog("发送任务成功" + task.ID, task.OperID, 1);
else
{
if (taskXML.Length > 0)
workMoveBack(task.OperID, task.WorkID, task.BatchID, 'M');
}
}
catch (System.Exception e)
{
Business.addLog("发送任务失败:" + task.ID + e.Message, task.OperID, 1);
if (taskXML.Length > 0)
workMoveBack(task.OperID, task.WorkID, task.BatchID, 'M');
}
}
#region WCF回调接口:
ITaskCallback callback
{
get { return OperationContext.Current.GetCallbackChannel<ITaskCallback>(); }
}
#endregion
}
客户端回调代码:
public class CallbackHandler : ITasksServiceCallback
{
public bool SendTask(InputTest.Test.Task task)
{
try
{if (Form1.nBaseID != task.BaseID)
{
Business.addLog("BaseID不相等:" + task.ID + " Form1.nBaseID=" + Form1.nBaseID.ToString() + " task.BaseID=" + task.BaseID.ToString(),1,0);
return false;
}
else
{
Form1.m_NewTask = task;
Business.addLog("引擎送来任务:" + task.ID + " nBaseID=" + task.BaseID.ToString(), 1, 0);
Form1.getTaskEvent.Set();
return true;
}
}
catch (Exception e)
{
Business.addLog("回调异常:" + e.Message, 1, 0);
return false;
}
}
}
答案
-
你好,
请加上:
[
CallbackBehavior(UseSynchronizationContext = false)]
public class CallbackHandler : ServiceReference.ITasksServiceCallback
Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us.- 已标记为答案 chenzhit 2009年9月24日 7:55
全部回复
-
你可以看看之前的一个讨论,http://social.msdn.microsoft.com/Forums/en-US/wcfzhchs/thread/a686462f-a342-4999-a881-31d3db2ad7f2。
当时讨论到回调的问题。
有可能出现死锁。然后超时异常。
另外你可以试验把这个00:02:00,修改为00:10:00,看看,我怀疑你是超时时间设置2分钟,太短了。
你的拔插网线很可能花费了2分多钟。
Frank Xu Lei--谦卑若愚,好学若饥
专注于.NET平台下分布式应用系统开发和企业应用系统集成
Focus on Distributed Applications Development and EAI based on .NET
欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum -
由于业务和其他方面的考虑所以超时时间不能设置得太长,如果等待的时间太长任务会卡在系统中无法处理而超时。
网上很多关于解决阻塞问题的方法都试过,貌似没用。刚看到一个资料好像有点像,就是错误契约。
http://book.csdn.net/bookfiles/628/10062820200.shtml
“如果客户端回调抛出的异常属于回调错误契约列出的异常,或者回调抛出一个FaultException异常,那么异常并不会导致回调通道发生错误,我们能够捕获异常,继续使用回调通道。然而,如果其中一个异常不属于错误契约的一部分,那么在抛出该异常之后,服务调用应会避免使用回调通道。”
我现在怀疑是不是因为断网或服务端关闭过导致了一个不属于错误契约内的异常,在再次开启服务端捕获该异常,但它却导致通道出现错误,因此服务无法重用它,所以后续的回调都不可用。 -
你好,
请问你是在什么时候关闭服务器端程序的?是在 1.客户端发起gettask请求 这之后 2.服务端从数据库中得到任务后调用回调sendtask把任务送到客户端 这之前吗? 异常是在服务器端被抛出还是在客户端抛出? 如下设置是否产生一样的结果?
[OperationContract(IsOneWay=true)]
bool SendTask(Task task);
Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us. -
你好,
能够上传一个重现问题的项目到http://skydrive.live.com/吗?请在这里帖下下载链接.我测试一下看看.
Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us. -
那谢谢了!
http://cid-45cad4abc91d67f0.skydrive.live.com/self.aspx/.Public/Artech.ThreadAffinity.rar
这个是我在网上下的,它的现象和我的有点像,在客户端的窗体上“+”两边编辑框随便填个数,然后点“=”按钮即可。在接口连续调用了几次之后就一直连续超时。那麻烦帮我看看是哪出了问题? -
你好,
服务器端的maxConcurrentSessions默认值为10,只允许同时有10个会话.所以在回调完成后应该关闭会话.可以用下面的方法设置:
public interface ICalculateCallback{
[
OperationContract(IsOneWay = true,IsTerminating = true)]
void DisplayResult(double result);
}
[
ServiceContract(CallbackContract = typeof(ICalculateCallback), SessionMode = SessionMode.Required)]
public interface ICalculate
{
[
OperationContract(IsOneWay=true)]
void Add(double op1, double op2);
}
Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us. -
http://cid-45cad4abc91d67f0.skydrive.live.com/self.aspx/.Public/%e5%8f%8c%e5%b7%a5%e5%9b%9e%e8%b0%83%e9%97%ae%e9%a2%98Demo%e7%a8%8b%e5%ba%8f.rar
我把我的程序改了一下,上面是下载连接,客户端程序可以随便用一个例如“5001”密码“000”的用户名和密码登陆,在Form1里有一个取任务线程getTaskThread(),在这个线程里调用取任务接口。当服务端开启,客户端程序登录,线程启动会取到一个模拟任务,在客户端界面上会显示取到的任务,按F1能提交任务,任务提交后会接着取下一任务。这样正常操作没有问题,然后在服务端的getTask接口实现函数的callback.SendTask(task)处定个调试断点,当程序走到此断点处时将服务程序关闭,等待1分钟左右重新将服务端开启,此时服务端回调接口会一直报超时异常。麻烦你再帮我看看,谢谢!有什么问题可以发邮件www.chenz@Sunyard.com和我核实。 -
http://cid-45cad4abc91d67f0.skydrive.live.com/self.aspx/.Public/Demo.rar
我稍微将代码整理了一下,我的客户端是做了一个解析XML以及根据它创建控件并显示的操作,这部分操作如果去掉好象就无法重现问题了,客户端中一些无关的代码我都收起来了,你只用关注Form1.cs中的GetTaskThread()和CallbakHander,具体说明我在代码里注释了。服务端能去的我都去掉了。我自己之前也自己另外写了一个简单的Demo程序,可就是怎么也试不出来,所以也只能将我原先的项目程序去掉一些东西后试了。很是郁闷啊!真的要谢谢你了。 -
http://cid-45cad4abc91d67f0.skydrive.live.com/self.aspx/.Public/Demo.rar
我根据跟踪到得问题重新写了一个Demo,客户端只用点击“确定”即可开启取任务线程,待正常取了几个任务后,关闭服务端程序。过20秒左右再开启服务端就无法正常通信,报超时异常。麻烦各位版主帮我看看。谢了! -
你好,
请加上:
[
CallbackBehavior(UseSynchronizationContext = false)]
public class CallbackHandler : ServiceReference.ITasksServiceCallback
Please remember to mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework http://cfx.codeplex.com/! If you have any feedback, please tell us.- 已标记为答案 chenzhit 2009年9月24日 7:55
-
谢谢Allen Chen - MSFT,真是这个问题。我很晕啊,我这个方法以前早就试过了,不知道问什么当时试过了感觉没用。我同事当时也试过,当时他在回调中加了SynchronizationContext.Post()这个方法,貌似没用,所以也没再试。以前一直对WCF不是很熟悉,通过这次的问题也学习了不少东西,感谢各位的解答。