《你必须知道的.NET》网站 | Anytao技术博客
[玩转Silverlight]第一回:基础篇,品尝与HttpHandler通信
发布日期:2009.01.20 作者:Anytao
© 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。
Silverlight实在是带给我们很多的惊喜和收获,作为2009年的目标之一(详见我的2008,专注而行),未来的日子我就将与银光相伴,玩玩Silverlight这个超酷感受的技术精灵。
作为[玩转Silverlight]开篇的系列,本文开始将Silverlight的体验和学习做以系列报道,作为系列文章我将从以下几个方面着手记录:
- 基础篇,讲述技术基础,例如本篇分析与HttpHandler通信的实现细节;
- 深入篇,讲述技术本质,解开应用和基础谜团,例如DependencyProperty、CrossDomain Policy以及CoreCLR等相关深入内容;
- 应用篇,以例讲理,通过小实例分享大技术;
- 翻译篇,翻译国外优秀的Silverlight技术贴,师夷长技以制夷;
- 推荐篇,推荐好的系列,推荐好的作品,推荐好的文章。
言归正传,我们开始第一回的分享之旅。以HttpHandler方式进行数据通信,是Silverlight不可拒绝的交互方式,关于HttpHandler不是本文探讨的重点,我们的目标是通过应用实例来品尝与HttpHandler通信的常见应用,为你的代码提供更多数据交互的选择方式,同时解决通信过程中的细枝末节。
基础课堂
基础课堂将以简短的论述,讨论技术要点,今天的主角是WebClient、WebRequest/WebResponse和HttpHandler。
WebClient
WebClient是个好东西,在与服务数据进行发送和接收式的太极套路中,WebClient以其简单性、易用性而名声大震,简单的说WebClient就是对WebRequest和WebResponse的封装,以发送请求而言,本质上正是通过WebRequest来实现资源请求的,这大大简化了操作模型,使得应用Uri进行资源请求和接收的操作异常顺手,这源于其提供了以下的几个方法:
- OpenWrite/OpenRead
- UploadData/DownloadData
- UploadFile/DownloadString
- UploadString/DownloadString
同时每个方法都提供了相应的异步调用方法,例如OpenWriteAsync、UploadDataAsync等,为实现基于WebClient的数据通信提供了很多支持,方便我们在后文轻松的应用。
WebRequest/WebResponse
顾名思义,WebRequest和WebResponse是分别用于发送请求和响应请求的。有意思的是,在.NET中的WebRequest和WebResponse是两个抽象类型,创建一个WebRequest或WebResponse实例的一般方法是:
WebRequest request = WebRequest.Create(uri);
通过在Create方法中指定不同uri的参数来创建不同类型的WebRequest具体实例,例如HttpWebRequest实例或者FileWebRequest实例。熟悉工程方法模式的读者不难发现,原来.NET FCL中处处有经典,只需稍微深入的研究一下IWebRequestCreate与WebRequest之间的关系,就会为简单的request实例化过程感到惊讶,这不过是基础论述中的小小插曲,但愿没有扫您继续关注Silverlight的兴致。
以WebRequest和WebResponse方式进行数据通信,我们将在后文以实例分析。同时,应当注意的是,不管是WebClient方式还是WebRequest方式,Silverlight中所有的数据通信,必须以异步方式进行。
HttpHandler
简单来说,HttpHandler是ASP .NET的Http请求处理中心,不同的文件类型通过提供不同的handler进行分派处理,大部分的操作由ASP .NET内置handler进行处理,而很多时候自定义Handler同样有其市场,在.NET中自定义handler一般需要实现IHttpHandler接口,
public interface IHttpHandler { bool IsReusable { get; } void ProcessRequest(HttpContext context); }
由其接口定义可知,IsResuable属性指示是否可以重用于其他IHttpHandler实例,而ProcessRequest方法中则实现自定义的http请求处理逻辑。
实例分析
下面我们以一个简单的实例为例,来分析两种方式操作下与HttpHandler进行数据交互的各种方式,首先做一点必要的准备在新建的Silverlight项目中建立必要的UI准备:
<StackPanel Orientation="Vertical"> <TextBox Margin="20, 5, 20, 5" x:Name="name" /> <TextBox Margin="20, 5, 20, 5" x:Name="pwd" /> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Button x:Name="btnGetByWebClient" Width="200" Content="GetByWebClient" Click="btnGetByWebClient_Click" /> <Button x:Name="btnGetByWebRequest" Width="200" Content="GetByWebRequest" Click="btnGetByWebRequest_Click" /> StackPanel> <TextBlock x:Name="result" Margin="20, 5, 20, 5" Text="Result: " /> <TextBlock x:Name="copyright" Margin="5" Text="@ 2009, Anytao.com" Foreground="Red" HorizontalAlignment="Center" /> StackPanel>
目的是通过检测Name和Password来判断输入的用户是否合法,执行的判断逻辑交由Handler来执行,而通过WebClient方式或者WebRequest方式请求和响应数据通信,所以Handler的逻辑也很简单:
// Release : 2009/01/20
// Author : Anytao, http://www.anytao.com
public class UserHandler : IHttpHandler, IRequiresSessionState { public void ProcessRequest(HttpContext context) { string name = context.Request.QueryString["name"]; string pwd = context.Request.QueryString["pwd"]; string result = ValidateUser(name, pwd); context.Response.ContentType = "application/x-www-form-urlencoded"; if (string.IsNullOrEmpty(result)) { context.Response.Write("Null"); } else { context.Response.Write(result); } } private string ValidateUser(string name, string pwd) { if (name.ToLower().CompareTo("anytao") == 0 && pwd.ToLower().CompareTo("123") == 0) { return name + " is a authorized user."; } else { return name + " is invalid user."; } } public bool IsReusable { get { return false; } } }
下面继续数据通信部分的实现。
WebClient方式
对于这种应用WebClient提供了最简单的理想方式,可以选择相应的既存方法处理不同数据通信的需求,例如在本例中我们将通过DownloadString下载从handler处理之后的响应:
// Release : 2009/01/20
// Author : Anytao, http://www.anytao.com
private void GetResultByWebClient(string name, string pwd) { string absolutePath = HtmlPage.Document.DocumentUri.AbsoluteUri; string address = absolutePath.Substring(0, absolutePath.LastIndexOf('/')) + "/Handler/UserHandler.ashx?name=" + name + "&pwd=" + pwd; Uri uri = new Uri(address); WebClient client = new WebClient(); client.DownloadStringCompleted += (sender, e) => { if (null == e.Error) { result.Text = e.Result; //Call other service here to continue operation } else { MessageBox.Show(e.Error.Message); } }; client.DownloadStringAsync(uri); }
注意,以QueryString进行数据传递并非一成不变的方式,不同浏览器对于Url的长度和编码都有不同的规则,例如大数据量通信情况下应该考虑以UploadString方式进行,通过Http Post方法向Handler发送请求,我们将在下回中讲述序列化主题时进行相关的讨论和应用示例。
WebRequest/WebResponse方式
以WebRequest方式进行数据通信,实现相同的请求操作,需要如下的实现:
// Release : 2009/01/20
// Author : Anytao, http://www.anytao.com
private void GetResultByWebRequest(string name, string pwd) { string absolutePath = HtmlPage.Document.DocumentUri.AbsoluteUri; string address = absolutePath.Substring(0, absolutePath.LastIndexOf('/')) + "/Handler/UserHandler.ashx?name=" + name + "&pwd=" + pwd; Uri uri = new Uri(address); WebRequest request = WebRequest.Create(uri); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.BeginGetRequestStream(new AsyncCallback(RequestReady), request); } private void RequestReady(IAsyncResult ar) { WebRequest request = ar.AsyncState as WebRequest; using (System.IO.StreamWriter sw = new System.IO.StreamWriter(request.EndGetRequestStream(ar))) { sw.Write("Post data to server."); } request.BeginGetResponse(new AsyncCallback(ResponseReady), request); } private void ResponseReady(IAsyncResult ar) { WebRequest request = ar.AsyncState as WebRequest; using (WebResponse response = request.EndGetResponse(ar)) { using (System.IO.Stream stream = response.GetResponseStream()) { using (System.IO.StreamReader reader = new System.IO.StreamReader(stream)) { Dispatcher.BeginInvoke((InvokeDelegate)BindAndNext, reader.ReadToEnd()); } } } } private void BindAndNext(string result) { if (!string.IsNullOrEmpty(result)) { this.result.Text = result; //Call another WCF Service continuously } else { MessageBox.Show("Error"); } }
最后,欣赏以下应用示例,品尝一下Silverlight下的数据通信体验,收获更多关于Silverlight的美妙感受:
另外,提及HttpHandler,另一个重要的问题是关于Session的处理,这同样是Silverlight开发中可能关注的问题。
关照Session
在HttpHandler中使用Session,必须实现IRequiresSessionState或者IReadOnlySessionState接口,
public class UserHandler : IHttpHandler, IRequiresSessionState { }
二者的区别是:
- IReadOnlySessionState,提供了Session状态值的只读访问权限
- IRequiresSessionState,提供了Session状态值的读写权限
细心的读者会发现这两个接口都是空接口,没有任何方法签名,只是作为标记接口,因此必须在自定义Handler中实现相应的接口才赋予了处理程序相应的操作权限,否则通过Session进行读写操作都返回null值。如本例UserHandler所示,实现IRequiresSessionState接口将使得在UserHandler中进行Session的读写处理变成可能,从而实现更多在Silverlight端与Web端的数据交互手段。
实际上,在进行Web通信的操作中简单的string传递只是冰山一角,更多的操作设计到对实体类型在不同环境的传递和交互,以本文的实例而言Silverlight客户端向Server端发送的name和pwd换成一个用户列表信息或者更加复杂的自定义类型,而Server端返回的请求也不仅仅是简单字符串(name + " is a authorized user."),那么通过querystring进行简单的数据传递将变的困难,我们将在下回探讨通信过程的另一个环节,那就是序列化和编码。
Anytao.SLScenario.AccessHandler.rar
anytao | © 2009 Anytao.com
2009/01/20 | http://anytao.cnblogs.com/
本文地址:http://www.cnblogs.com/anytao/archive/2009/01/20/anytao_silverlight_01_communication_handler.html
本文以“现状”提供且没有任何担保,同时也没有授予任何权利。 | This posting is provided "AS IS" with no warranties, and confers no rights.
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。