说明:本系列基本上是《WPF揭秘》的读书笔记。在结构安排与文章内容上参照《WPF揭秘》的编排,对内容进行了总结并加入一些个人理解。
这一部分我们重点讨论下Silverlight的网络与通讯功能。2.0版起,Silverlight支持多种模式的网络访问,从最原始的Silverlight控件支持的JavaScript方法,到Silverlight Framework内置的通过C#操作的各种类,几乎可以实现任意你想实现的功能。下面我们逐一讨论这些方法:
-
通过Silverlight控件的JavaScript支持
这种方式的最终目的无非是把通过JavaScript获取的网络数据赋给Silverlight中的元素,代码大致如下所示:
1 var valFromNet; 2 var SL = document.getElementById("silverlightPlugIn"); 3 SL.content.findName("txt").Text = valFromNet;
-
编写使用xmlHttpRequest组件的JavaScript以Ajax方式异步获取数据
我们通过如下代码段看一下这种方式的实现:
1 function getAsyncResult() { 2 xmlHttp = new XMLHttpRequest(); 3 xmlHttp.open("GET", "http://localhost:36360/ServerTime.ashx", true); 4 xmlHttp.onreadystatechange = handleAJAXCallback; 5 xmlHttp.send(null); 6 } 7 8 function handleAJAXCallback() { 9 if ((xmlHttp.readyState == 4) && (xmlHttp.status == 200)) { 10 var SL = document.getElementById("silverlightPlugIn"); 11 SL.content.findName("txt").Text = xmlHttp.responseText; 12 } 13 }
可见,在回调函数中将异步获取的结果设置给Silverlight的元素。这个例子中我们访问的是一个ASP.NET编写的HttpHandler,可以将其换成其它任何可得到数据的Url。值得一提的在回调函数中队XmlHttpRequest的状态进行了检测,4即表示请求完成。
-
在Silverlight项目中添加ASP.NET Web服务的引用,并访问
在Silverlight中添加了对包含标记了[System.Web.Script.Services.ScriptService]属性的服务(方法也需要被标记为[WebMethod])的引用后,并页面中使用ScriptManager控件引用服务时,会自动生成JavaScript代理,这正是我们需要的东西,我们通过它来访问服务。完成上面的操作后我们就可以使用如下的JavaScript代码访问Web Service来获取我们想要的数据。
注意在生成的JavaScript代理中我们使用WebServiceName.WebMethod这样的对象名来访问服务。
1 function onLoad() 2 { 3 Service.getTime(onSuccess, onFailed,""); 4 } 5 6 function onSuccess(result) 7 { 8 var sl = document.getElementById("silverlightPlugIn"); 9 sl.content.findName("txtShort").Text = result.strShortTime; 10 sl.content.findName("txtLong").Text = result.strLongTime; 11 } 12 13 function onFailed(result) 14 { 15 alert(result); 16 }
此处得到的result这个对象 ,已经被序列化为JSON格式。
-
Silverlight Framework中的WebClinet与WebRequest方法
首先我们来了解下WebClient的功能,在使用.NET进行Silverlight编程时,WebClient提供了最简单易用的网络访问功能,这个类的两个方法DownloadStringAsync与OpenReadAsync分别用来获取字符串及获取其它类型的数据,这些方法也是异步方法对应的回调函数分别为DownloadStringCompleted和OpenReadCompleted。下面的代码使用DownloadStringAsync演示了WebClient的使用:
1 public Page() 2 { 3 InitializeComponent(); 4 WebClient cl = new WebClient(); 5 Uri uri = new Uri("http://localhost:36360/Web/Time.ashx"); 6 7 cl.DownloadStringCompleted += new DownloadStringCompletedEventHandler(cl_DownloadStringCompleted); 8 cl.DownloadStringAsync(uri); 9 } 10 11 void cl_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 12 { 13 txtTime.Text = e.Result; 14 }
注意,使用WebClient需要添加对System.Net命名空间的引用。WebClient中其它常用属性还包括IsBusy,当数据在传输过程中此值返回true。WebClient中CancelAync方法用来取消正在进行的异步传输,并且此时DownloadStringCompleted/OpenReadCompleted事件参数的Cancelled属性会被置为true。
接下来要介绍的是WebRequest类,这个类用来实现标准HTTP请求,主要包括一些通过POST来访问的地址。这个类的使用与.NET Framework中的HttpWebRequest很相似,下面给出一段核心代码作为示例:1 private void b_Click(object sender, RoutedEventArgs e) 2 { 3 Uri uri = new Uri("http://localhost:22602/WebRequestTest_Web/SubmitForm.ashx"); 4 WebRequest rq = WebRequest.Create(uri); 5 rq.Method = "POST"; 6 rq.ContentType = "application/x-www-form-urlencoded"; 7 rq.BeginGetRequestStream(new AsyncCallback(RequestReady), rq); 8 rq.BeginGetResponse(new AsyncCallback(ResponseReady), rq); 9 } 10 void RequestReady(IAsyncResult aR) 11 { 12 WebRequest rq = aR.AsyncState as WebRequest; 13 Stream rqStream = rq.EndGetRequestStream(aR); 14 StreamWriter w = new StreamWriter(rqStream); 15 w.Write("t1=" + t1.Text + "&"); 16 w.Write("t2=" + t2.Text + "&"); 17 w.Write("t3=" + t3.Text ); 18 w.Flush(); 19 }
上面代码中在获取请求数据与获取响应数据时都是发起的异步请求,在获取响应数据完成时需要下面的回调函数处理完成事件:
1 void ResponseReady(IAsyncResult aR) 2 { 3 WebRequest rq = aR.AsyncState as WebRequest; 4 using(WebResponse rs = rq.EndGetResponse(aR)) 5 using (Stream rpStream = rs.GetResponseStream()) 6 { 7 StreamReader rdr = new StreamReader(rpStream); 8 string postStatus = rdr.ReadToEnd(); 9 } 10 }
-
在Silverlight中使用WCF
Silverlight Framework中System.ServiceModel中的类提供了Silverlight对WCF的支持。下面的小例子给出了演示,我们通过在Visual Studio中添加WCF的引用来生成一个代理,这大大减少了编码的复杂度。我们逐段代码分析这个例子:
首先是一个DataContract,这是服务器端与客户端传输数据类型的一个契约:1 [DataContract] 2 public class Person 3 { 4 public Person(string strName, string strAge) 5 { 6 Name = strName; 7 Age = strAge; 8 } 9 [DataMember] 10 public string Name { get; set; } 11 [DataMember] 12 public string Age { get; set; } 13 }
然后是服务代码,这其中包括服务契约与服务实现:
1 [ServiceContract] 2 public interface IPersonService 3 { 4 [OperationContract] 5 Person[] getPeople(); 6 } 7 8 public class PersonService : IPersonService 9 { 10 public Person[] getPeople() 11 { 12 Person[] people = 13 { 14 new Person("Derek Snyder","32"), 15 new Person("Yoshi Latimer","19"), 16 new Person("Mark Steel","31") 17 }; 18 return people; 19 } 20 }
对于这个简单的示例我们使用basicHttpBinding,服务的config中ServiceModel这部分参考如下代码:
1 <system.serviceModel> 2 <behaviors> 3 <serviceBehaviors> 4 <behavior name="PersonServiceBehavior"> 5 <serviceMetadata httpGetEnabled="true"/> 6 <serviceDebug includeExceptionDetailInFaults="false"/> 7 </behavior> 8 </serviceBehaviors> 9 </behaviors> 10 <services> 11 <service behaviorConfiguration="PersonServiceBehavior" name="PersonService"> 12 <endpoint address="" binding="basicHttpBinding" contract="IPersonService"> 13 <identity> 14 <dns value="localhost"/> 15 </identity> 16 </endpoint> 17 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 18 </service> 19 </services> 20 </system.serviceModel>
以上就是服务部分重要的代码,在添加了WCF服务引用后我们就可以使用如下的代码在WCF中访问服务:
1 public Page() 2 { 3 InitializeComponent(); 4 Binding binding = new BasicHttpBinding(); 5 EndpointAddress endPoint = new EndpointAddress("http://localhost:36360/WCFService/PersonService.svc"); 6 PSProxy.PersonServiceClient client = new PSProxy.PersonServiceClient(binding, endPoint); 7 client.getPeopleCompleted += new EventHandler<PersonService.PSProxy.getPeopleCompletedEventArgs>(client_getPeopleCompleted); 8 client.getPeopleAsync(); 9 }
回调函数中我们把得到的对象绑定到ItemsControl的数据模板中:
ItemControl的XAML:1 <ItemsControl x:Name="_item"> 2 <ItemsControl.ItemTemplate> 3 <DataTemplate> 4 <StackPanel Orientation="Vertical"> 5 <StackPanel Orientation="Horizontal"> 6 <TextBlock FontWeight="Bold" Text="{Binding Name}" /> 7 <TextBlock Text=" : "></TextBlock> 8 <TextBlock FontWeight="Bold" Text="{Binding Age}" /> 9 </StackPanel> 10 </StackPanel> 11 </DataTemplate> 12 </ItemsControl.ItemTemplate> 13 </ItemsControl>
回调函数:
1 void client_getPeopleCompleted(object sender, PersonService.PSProxy.getPeopleCompletedEventArgs e) 2 { 3 _item.ItemsSource = e.Result; 4 }
客户端的配置在添加引用时自动生成不再赘述。
以上这些就是Silverlight中访问网络的主要方式。
本文完