在Silverlight开发基于http协议客户端连接器(一)
2010-09-02 17:42 姜 萌@cnblogs 阅读(638) 评论(0) 编辑 收藏 举报之前在一个项目中需要Silverilght应用与基于java 的web应用进行通讯。我当时 的可选方案有三个:
1.通过HTML Bridge,silverlight调用外部js代码,js再通过ajax与服务器通讯,在获得返回的数据后js再调用silverlight的方法。具体来讲,主要是通过HtmlPage.Document操作DOM,HtmlPage.Window调用js function。通过ScriptableMemberAttribute标注来是方法对js可见,并且在html中包含silverlight 的<object>中加入<param name="enableHtmlAccess" value="true" /> 使其具备相关权限。
关于有关HTML Bridge的详细用法您可以参见MSDN中的:HTML Bridge: Interaction Between HTML and Managed Code
2.silverlight直接与服务器通讯。虽然silverlight应用(非OOB模式)承载于HTML中但silverlight是一个完整的RIA,其实对于这样一个需求而言,我们完全可以让silverlight自己解决。silverlight为我们提供了两个方便http通讯的类型:WebClient和HttpWebRequest,相比之下WebClient更傻瓜一些,如其名,就是一个封装好的mini web客户端。笔者笔者以前在wpf开发中也使用webclient解决类似问题,可是偏偏silverlight的WebClient缩水太严重,没有CookieContainer属性,而且像修改HTTP Headers这种正常的操作在silverlight版本中居然出错,相比而言HttpWebRequest可以提供更灵活的操作,具体方案在下面讨论。
3.使用Web Service。虽然在.NET平台下wcf的功能更为强大并且同样是基于SOAP,像BingMap为silveright提供的都是wcf服务,但对于跨平台的通讯而言web service在java平台已经有像axis这样的成熟产品。WS更容易被人们接受。不过考虑到java这边自动生成silverlight客户端代码不方便所以暂不考虑。
Silverlight中WebClient的局限性以及遇到的问题
下面代码使用的是完整BCL中的System.Net.WebClient,可以正常获得响应头中的SESSIONID,。
WebClient client = new WebClient();
client.DownloadStringCompleted += (o, e)
=> Console.WriteLine(client.ResponseHeaders[HttpResponseHeader.SetCookie]);
client.DownloadStringAsync(new Uri("http://www.mywebsite.com/testservice.do%22));
这样我们只需通过anotherClient.Headers[HttpRequestHeader.Cookie] = ……将得到的SET-COOKIE值(里面有sessionid)设置进去,这样下次访问时就可以保持住session。
但是在silverlight中就出现问题了,首先就没有HttpResponseHeader,并且ResponseHeaders竟然是null的 ,更不解的是居然不能设置WebClient.Headers,每次设置都会引发异常 。得不到设置不了Headers也得不到ResponseHeaders中的cookie值,也就是说使用silverlight的WebClient没法保持住session。
好吧,几人silverlight版本的webclient有如此多的局限性,我们就尝试使用HttpWebRequest(如果这哥们再出问题那就干脆用socket实现http算了。。)
定制自己的WebClientEx
为了方便别人使用,我们提供与WebClient方法类似的两个委托签名:public event Action<string> DownloadStringCompleted,public event Action DownloadError。实现起来也容易,就是组合一个HttpWebRequest,使用.NET中惯用的二段式异步编程,代码如下。
{
private readonly static string No_Cache = "no-cache";
private readonly static string Tricky_NeverIfNoneMatch = "2701-4c4585e8";
private HttpWebRequest _request;
public WebClientEx()
{
}
public void SendAsync(string url, CookieContainer cookie)
{
_request = HttpWebRequest.CreateHttp(url);
_request.CookieContainer = cookie;
_request.Headers[HttpRequestHeader.CacheControl] = No_Cache;
_request.Headers[HttpRequestHeader.IfNoneMatch] = Tricky_NeverIfNoneMatch;
_request.BeginGetResponse(onResponseCallback, null);
}
private void onResponseCallback(IAsyncResult ar)
{
try
{
WebResponse response = _request.EndGetResponse(ar);
string result = null;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
}
if (DownloadStringCompleted != null)
DownloadStringCompleted(result);
}
catch (Exception )
{
if (DownloadError != null)
DownloadError();
}
}
public event Action<string> DownloadStringCompleted;
public event Action DownloadError;
}
这样:
WebClientEx client = new WebClientEx();
var cookie = CookieContainer();
client.SendAsync(URI1, cookie);
client.SendASync(URI2, cookie);
当第二次调用时就能够保持住session。