Silverlight 结合WCF Duplex Service聊天程序出炉

翻译了 利用 WCF duplex Service 【推送】数据到Siliverlight客户端 的双向通讯例子 收益菲浅, 终于通讯真正做起来了, 刚做好的聊天程序, 后面再补充笔记, 把一些关键问题解决调, 在优化一下.

访问地址: http://www.shareach.com:81/chat

代码下载:http://www.cnblogs.com/yinpengxiang/archive/2009/03/30/1424724.html

以前js版本的: http://www.shareach.com/chat.aspx对应

看了一周的WCF终于有点成果了. 服务端参考了MSDN的这个文章, 客户端参考了MSDN这个文章

看大家登录后测试情况, 这个 双向通讯还是不稳定, 经常有js错误出现,但是不影响正常使用

后续计划:

  • 做公聊的聊天室,现在只有私聊的
  • 完成登录状态即时更新, 现在人家走了一年也不知道
  • 把前面测试的上传功能结合进来
  • 想做一个相册

这么多功能先想想,不知道要到猴年马月搞定

遇到的问题/原因和解决办法吧

1.PollingDuplexHttpBinding.ReceiveTimeout 对应的超时问题 和 这个问题发现后的代码修改方式

这个问题用作IM通讯项目里可能会碰到, 这个属性是针对监听超时, MSDN上描述是”Gets or sets the interval of time that a connection can remain inactive, during which no application messages are received, before it is dropped.” 我开始一度以为,这个是针对整个通道的, 所以一直没有搞明白消息收发仍在正常继续,但又会有超时报错, 经过几天的反复验证,终于发现问题原因和症结了. 我出的错误信息如下:CompleteReceive:Receive on local address http://docs.oasis-open.org/ws-rx/wsmc/200702/anonymous?id=ce16853b-f9cb-47e8-b812-3ea66bda0c45 timed out after 00:01:30. The time allotted to this operation may have been a portion of a longer timeout.这是一个普通的超时错误, 这个错误不是针对通道的, 而是对每个异步监听的错误, 我把我错误原因描述一下, 但是没有想好解决方法.

这个错误是我启动了很多异步监听(不是一个), 我是抄MSDN上的例子. 每次发送消息后我都会调用LoopRecive等消息,然后消息接受完了以后我还调用LoopRecive等消息. 有很多这个监听轮询, 导致超时的.  MSDN上的例子的void CompleteOpenChannel(IAsyncResult result)调用了ReceiveLoop(channel); void CompleteReceive(IAsyncResult result)里面有调用了 ReceiveLoop(channel); 他这个是同步方式在循环发送信息,所以不会出超时异常,我把 SendMessage做了一个消息缓冲池, 每次有消息我就批量的发出去了 而且都调用ReceiveLoop,导致很多监听等待. 主要是例子里面所有的通讯都是顺序的, 但是真实使用的时候不可能这样完全顺序的. 有可能几个消息同时到达客户端, 为了保证消息正常到达,我又有回复机制,这就导致又有RecieveLoop循环,呵呵恶性循环. 还没想到好办法,只是把他try catch调了.

其实我觉得这是一个好处,反正都是异步监听,异步发送,不会影响到通道, 所以我把代码做了修改, 把消息池都去掉了, 呵呵, 看下面:

MSDN相关代码

MSDN相关代码

改了一下流程和发送方式, 去掉了前面加的消息发送池, 既然超时只是针对每次监听回调, 那么我可以怎么发消息都没事了, 也就是连接完成后,我把Channel提出来了, 把发送功能(SendMessage)单独的抛出来了, 以后就一直用它好了,除非通道异常了, 至于通道异常不是这个主题了

我的代码

面的代码中,我可以任意的地方调用SendMessage, 这样就封装成了一个只有几个口的通讯类了, 其它都用了异常属性方法回调, 比较懒, 都是同步调用的,没有用异步方式. 那么那个异常就让他异常去吧, 反正不影响我通讯. 除非后面有好的解决方法.

还有一个就是那个SendMessageState类, 为了在异步发送完成后, 如果出错,知道原始消息是什么了, 但是有个问题就是站着内存, 不过消息不大,呵呵.

2. 异步调用,其它线程访问UI

前面好多地方为了使Silverlight不出错, 都加了Try Catch了, 也没处理(习惯不好,为了快速验证学过的东西), 而且很多回调都是同步的, 在界面上都没有看到错误在哪, 经常出了莫名奇妙的问题, 后来发现很多是因为通道接收到的消息都是uiThread.Post()方法出来的,导致了这个冲突, 后来做了那个调试日志才发现的. 置于怎么访问更新和处理UI看Silverlight中 非UI线程更新UI 的几种方法, 这和WinForm有点类似.

3.全屏模式下键盘无效了

这个问题比较恶心, 我感觉应该是个开关, 微软解释是什么操作安全问题, 全屏不让随便碰屏幕什么的. 如果是开关多好, 开始全屏感觉慢爽的. 发现全屏不能输入, 就不爽了.

4.IE 8

Ie 8 从Beta 开始我就安装了一次,为了那个Dev tool(和firebug类似), 发现不好用, RC的时候又是装了卸了, 正式版还是一样, SL在上面好多问题(是一个在聊天室告诉我的), 包括cnblog版面都是不正常, 又卸了. 这个问题应该不是这个里面的问题, 罗列一下吧.

5.客户端退出让Service即时知道

退出或者异常退出,还没找到办法及时让Service监测到,只有等待session过期才能检测到, 只能把session值设置小一点. 不知道有没有其它办法, 让Service快速知道客户端断了.

 

总的感觉, WCF 非常强大, Silverlight结合WCF做RIA应用觉得比Flash强, 那个SmartFoxServer好难用啊, 而且那个代码太难受.

上次看了CodePlex上的一个开源代码, 上传大文件的, 我上传了7G还没死, 后来不敢继续了, 我把他改了一下上传照片, 网址是 http://www.shareach.com:81/upload, 客户端就处理图片,很爽.

 

后面还要继续研究WCF其它的东西. good good study, day day up.

posted @ 2009-03-23 00:18 shareach 阅读(4859) 评论(20) 编辑 收藏

 回复 引用 查看   
#1楼2009-03-23 15:00 | wanghualiang      
工作一忙就没有什么时间写博客,人就变懒了!相册MSDN上已经有一个写的还不错的!
 回复 引用 查看   
#2楼[楼主]2009-03-23 15:39 | sps.shareach.com      
呵呵,谢谢关注, MSDN上那个好像就是silverlight官方网站上的
silverlight官方网站上也有好几个,好像Blend的例子就有一个
我主要是以练手为主, sl和wcf, 做基于个人的登录, 聊天,相册,上传和文件管理
工作忙了什么都没时间做,这一阵子我在一个客户要求下,全是新东西, 不记下来下次又要查资料, 发日志比较勤快,呵呵

 回复 引用 查看   
#3楼2009-03-26 14:24 | 流牛木马      
哈哈,是我告诉你IE8测试不能通过的 :)
 回复 引用 查看   
#4楼[楼主]2009-03-26 23:17 | sps.shareach.com      
@流牛木马
呵呵, 我聊天室里面都乱名字对不上号的, 你和我说了不行, 就装了IE 8, 给我感觉就2个字"难用", 又卸载了, 已经是第三次卸载IE 8了
第一次为了开发人员工具, 第二次也是看看变好了没有, 这又一次. 呵呵不知道还有没有下次卸载

 回复 引用 查看   
#5楼2009-03-30 09:20 | sujiantao      
不错啊~
 回复 引用 查看   
#6楼2009-03-30 10:19 | mFrog      
--引用--------------------------------------------------
wanghualiang: 工作一忙就没有什么时间写博客,人就变懒了!相册MSDN上已经有一个写的还不错的!
--------------------------------------------------------

MSDN的相册在哪啊?能告诉我地址去学习下不?

 回复 引用 查看   
#7楼[楼主]2009-03-31 20:24 | sps.shareach.com      
--引用--------------------------------------------------
mFrog: --引用--------------------------------------------------
wanghualiang: 工作一忙就没有什么时间写博客,人就变懒了!相册MSDN上已经有一个写的还不错的!
--------------------------------------------------------

MSDN的相册在哪啊?能告诉我地址去学习下不?
--------------------------------------------------------
http://silverlight.net/community/communitygallery.aspx
这个上面有的, codeplex上也有几个,http://slideshow.codeplex.com/ http://myphotoindex.codeplex.com/ http://photoalbum.codeplex.com/

 回复 引用   
#8楼2009-04-01 17:02 | zft
楼主,我正在学习做silverlight的聊天室,请问可以发个源代码给我参考吗?你给的连接好像不能下载
 回复 引用 查看   
#9楼[楼主]2009-04-01 18:20 | sps.shareach.com      
@zft
不好意思,我是wss的建的网站, 忘了审核,现在好了

 回复 引用   
#10楼2009-04-01 19:33 | zft
能下了,谢谢楼主的无私奉献
 回复 引用 查看   
#11楼[楼主]2009-04-01 20:16 | sps.shareach.com      
@zft
不客气

 回复 引用   
#12楼2009-06-05 16:37 | xc27egg
我下载不了能不能发到我邮箱,谢谢, 50874613@qq.com
我最近也做这个聊天室的研究,共同进步

 回复 引用 查看   
#13楼[楼主]2009-06-05 20:52 | sps.shareach.com      
可以下载啊
 回复 引用 查看   
#15楼2009-07-18 22:47 | Chilli      
你好,我也在codeplex上下载了那个大文件上传的代码,也希望能够在上传图片时能在本地就把图片缩略了,是否可以使用你的代码,谢谢
pub123@126.com

 回复 引用 查看   
#16楼2010-04-08 11:38 | Nero.Pang      
楼主,跑起来有错误,半天没找着错误原因!请帮忙!
服务地址原是你demo的服务地址,后来我改成本地的了,服务也跑起来了,可登陆的时候就报下面的错误!
===================================================
TextBoxCompleteOnSend:System.ServiceModel.CommunicationException: 远程服务器返回了错误: NotFound。 ---> System.Net.WebException: 远程服务器返回了错误: NotFound。 ---> System.Net.WebException: 远程服务器返回了错误: NotFound。
位于 System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
位于 System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
位于 System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
--- 内部异常堆栈跟踪的结尾 ---
位于 System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
位于 System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
位于 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
--- 内部异常堆栈跟踪的结尾 ---
位于 System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
位于 System.ServiceModel.Channels.ClientPollingDuplexSessionChannel.SendAsyncResult.End(IAsyncResult result)
位于 System.ServiceModel.Channels.ClientPollingDuplexSessionChannel.OnEndSend(IAsyncResult result)
位于 System.ServiceModel.Channels.DuplexChannel.EndSend(IAsyncResult result)
位于 Shareach.SL.Chat.ClientRecv.CompleteOnSend(IAsyncResult result)
CompleteOnSend:System.ServiceModel.CommunicationException: 远程服务器返回了错误: NotFound。 ---> System.Net.WebException: 远程服务器返回了错误: NotFound。 ---> System.Net.WebException: 远程服务器返回了错误: NotFound。
位于 System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
位于 System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
位于 System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
--- 内部异常堆栈跟踪的结尾 ---
位于 System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
位于 System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
位于 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
--- 内部异常堆栈跟踪的结尾 ---
位于 System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
位于 System.ServiceModel.Channels.ClientPollingDuplexSessionChannel.SendAsyncResult.End(IAsyncResult result)
位于 System.ServiceModel.Channels.ClientPollingDuplexSessionChannel.OnEndSend(IAsyncResult result)
位于 System.ServiceModel.Channels.DuplexChannel.EndSend(IAsyncResult result)
位于 Shareach.SL.Chat.ClientRecv.CompleteOnSend(IAsyncResult result)

 回复 引用 查看   
#17楼[楼主]2010-04-08 22:10 | sps.shareach.com      
@Nero.Pang
还是Wcf service 没有或者sl的请求地址 配置错误

 回复 引用 查看   
#18楼2010-07-16 01:38 | customevalidator      
引用Receive on local address http://docs.oasis-open.org/ws-rx/wsmc/200702/anonymous?id=ce16853b-f9cb-47e8-b812-3ea66bda0c45 timed out after 00:01:30. The time allotted to this operation may have been a portion of a longer timeout.

这个东东我也遇到了,我是在ReceiveLoop里面判断发生异常就将通道关闭重新建立通道,并设大了ReceiveTimeout值来处理的,然后用户非正常退出我是用的服务端的通道closing事件来处理的;但是不能吃透WCF Duplex+SilverLight,所以通道经常出错,重新建立通道频繁,对此很没有信心

 回复 引用 查看   
#19楼2010-07-16 01:44 | customevalidator      
@Nero.Pang
兄弟,这个是SL SDK 2/3的问题,微软那个例子是基于SL2的,在SL3需要做修改:
1.MessageVersion由之前的Soap11=>MessageVersion.Soap12WSAddressing10

2.服务工厂那里添加终结点的地方需要作修改:
this.AddServiceEndpoint(
typeof(IDuplexService),
new CustomBinding(
pdbe,
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()),
"");

 回复 引用 查看   
#20楼[楼主]2010-07-16 11:31 | sps.shareach.com      
@customevalidator
对的,sl4好像没这个问题了