本文我们学习如何使用WebRequest类实现客户端和服务器端的通讯。
本例处理过程:在客户端,我们在文本框中输入任意文本,然后用POST方法向服务器端传递信息,服务器端收到从客户端传来的信息后做相应处理,再向客户端返回服务器端的信息,客户端收到服务器端信息后也做相应处理然后在客户端界面上显示处理结果。效果如下:
新建 Silverlight应用程序,命名为:SLWebRequestTest,在SLWebRequestTest.Web项目下,建立一个Handler,命名为:WebRequestHandler.ashx,它负责处理响应客户端请求并返回处理结果。
如下图:
1、建立程序界面
Page.xaml代码如下:
<UserControl x:Class="SLWebRequestTest.Page"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel Width="400" Height="250" Background="Wheat" >
<TextBlock Text="请输入传递到服务器的数据" TextAlignment="Center" Foreground="Red" Margin="2" FontSize="16"></TextBlock>
<TextBox x:Name="tbClientContent" Width="250"></TextBox>
<Button x:Name="btnGetData" Width ="200" Height="25" Content="获取数据" Click="btnGetData_Click" Margin="20"></Button>
<TextBlock Text="通过WebRequest从服务器取得的数据如下" TextAlignment="Center" Foreground="Red" Margin="2" FontSize="16"></TextBlock>
<TextBlock x:Name="tbRetText" Text="当前内容为空" TextAlignment="Center" Foreground="Green" FontSize="16"></TextBlock>
</StackPanel>
</UserControl>
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel Width="400" Height="250" Background="Wheat" >
<TextBlock Text="请输入传递到服务器的数据" TextAlignment="Center" Foreground="Red" Margin="2" FontSize="16"></TextBlock>
<TextBox x:Name="tbClientContent" Width="250"></TextBox>
<Button x:Name="btnGetData" Width ="200" Height="25" Content="获取数据" Click="btnGetData_Click" Margin="20"></Button>
<TextBlock Text="通过WebRequest从服务器取得的数据如下" TextAlignment="Center" Foreground="Red" Margin="2" FontSize="16"></TextBlock>
<TextBlock x:Name="tbRetText" Text="当前内容为空" TextAlignment="Center" Foreground="Green" FontSize="16"></TextBlock>
</StackPanel>
</UserControl>
2、客户端完成的工作
i、向服务器端POST客户端信息
ii、向服务器端发起异步请求
iii、接收服务器端返回的数据,做相应处理后显示在界面上。
Page.xaml.cs全部代码如下:
using
System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Threading;
namespace SLWebRequestTest
{
public partial class Page : UserControl
{
string clientInfoStr;
string serverInfoStr = "当前无信息";
private SynchronizationContext currentContext;
public Page()
{
InitializeComponent();
this.currentContext = SynchronizationContext.Current;
}
private void btnGetData_Click(object sender, RoutedEventArgs e)
{
//设置Uri地址
Uri endpoint = new Uri("http://localhost:54292/WebRequestHandler.ashx");
//获取POST到Server端的数据
clientInfoStr = this.tbClientContent.Text.ToString();
//首先对代表Web请求的对象进行实例化。但在此并不是使用构造函数来实例化对象,而是调用静态的WebRequest.Create()方法,
//WebRequest类是支持不同网络协议的类层次结构的一部分,为了给请求类型接收一个对正确对象的引用,需要一个工厂(factory)机制。WebRequest.Create()方法会为给定的协议创建合适的对象。
//WebRequest类代表要给某个URI发送信息的请求,URI作为参数传送给Create()方法。WebResponse类代表从服务器获取的数据。
WebRequest request = WebRequest.Create(endpoint);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
向服务器端POST信息#region 向服务器端POST信息
clientInfoStr = this.tbClientContent.Text.ToString(); //取得将要POST的信息
request.BeginGetRequestStream(new AsyncCallback(RequestCallBack), request);
#endregion
//说明:有的在此处把
// request.BeginGetRequestStream(new AsyncCallback(RequestReady), request);
// request.BeginGetResponse(new AsyncCallback(ResponseReady), request);
//写在一起,这样是没用的。 因为是在两个线程里处理的, 一开始请求就接收返回值了,所以必须把BeginGetResponse放到BeginGetRequestStream的回调函数中执行
}
POST信息到服务器端#region POST信息到服务器端
private void RequestCallBack(IAsyncResult asynchronousResult)
{
WebRequest request = (WebRequest)asynchronousResult.AsyncState;
Stream postStream = request.EndGetRequestStream(asynchronousResult);
string postData = String.Format(" ClientInfo = {0}", clientInfoStr);
try
{
using (StreamWriter writer = new StreamWriter(postStream))
{
writer.Write(postData);
writer.Flush();
}
}
catch (Exception ex)
{
string ke = ex.ToString();
}
向服务器端请求返回信息#region 向服务器端请求返回信息
//WebRequest类的一个特性就是可以异步请求页面。由于在给主机发送请求到接收响应之间有很长的延迟,因此,异步请求页面就显得比较重要。
//像WebClient.DownloadData()和WebRequest.GetResponse()等方法,在响应没有从服务器回来之前,是不会返回的。
//如果不希望在那段时间中应用程序处于等待状态,可以使用BeginGetResponse() 方法和 EndGetResponse()方法,
//BeginGetResponse()方法可以异步工作,并立即返回。在底层,运行库会异步管理一个后台线程,从服务器上接收响应。
//BeginGetResponse() 方法不返回WebResponse对象,而是返回一个执行IAsyncResult接口的对象。使用这个接口可以选择或等待可用的响应,然后调用EndGetResponse()搜集结果。
request.BeginGetResponse(new AsyncCallback(OnResponse), request);
#endregion
}
#endregion
接收服务器端的信息#region 接收服务器端的信息
protected void OnResponse(IAsyncResult ar)
{
WebRequest wrq = (WebRequest)ar.AsyncState;
//对应 BeginGetResponse()方法,在此处调用EndGetResponse()搜集结果。
//WebResponse类代表从服务器获取的数据。调用EndGetResponse方法,实际上是把请求发送给Web服务器,创建一个Response对象。
WebResponse wrs = wrq.EndGetResponse(ar);
// 读取WebResponse对象中内含的从服务器端返回的结果数据流
using (Stream responseStream = wrs.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream);
string retGet = reader.ReadToEnd();
serverInfoStr = retGet;
//通过Thread完成对UI的修改
//因为在多线程情况下,不能在背景线程里操作UI线程, 改为:
Thread mythread = new Thread(new ThreadStart(AcrossThread));
mythread.Start();
}
}
修改UI内容#region 修改UI内容
private void AcrossThread()
{
currentContext.Post(result =>
{
this.tbRetText.Text = serverInfoStr; //在此处修改UI内容
}, null);
}
#endregion
#endregion
}
}
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Threading;
namespace SLWebRequestTest
{
public partial class Page : UserControl
{
string clientInfoStr;
string serverInfoStr = "当前无信息";
private SynchronizationContext currentContext;
public Page()
{
InitializeComponent();
this.currentContext = SynchronizationContext.Current;
}
private void btnGetData_Click(object sender, RoutedEventArgs e)
{
//设置Uri地址
Uri endpoint = new Uri("http://localhost:54292/WebRequestHandler.ashx");
//获取POST到Server端的数据
clientInfoStr = this.tbClientContent.Text.ToString();
//首先对代表Web请求的对象进行实例化。但在此并不是使用构造函数来实例化对象,而是调用静态的WebRequest.Create()方法,
//WebRequest类是支持不同网络协议的类层次结构的一部分,为了给请求类型接收一个对正确对象的引用,需要一个工厂(factory)机制。WebRequest.Create()方法会为给定的协议创建合适的对象。
//WebRequest类代表要给某个URI发送信息的请求,URI作为参数传送给Create()方法。WebResponse类代表从服务器获取的数据。
WebRequest request = WebRequest.Create(endpoint);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
向服务器端POST信息#region 向服务器端POST信息
clientInfoStr = this.tbClientContent.Text.ToString(); //取得将要POST的信息
request.BeginGetRequestStream(new AsyncCallback(RequestCallBack), request);
#endregion
//说明:有的在此处把
// request.BeginGetRequestStream(new AsyncCallback(RequestReady), request);
// request.BeginGetResponse(new AsyncCallback(ResponseReady), request);
//写在一起,这样是没用的。 因为是在两个线程里处理的, 一开始请求就接收返回值了,所以必须把BeginGetResponse放到BeginGetRequestStream的回调函数中执行
}
POST信息到服务器端#region POST信息到服务器端
private void RequestCallBack(IAsyncResult asynchronousResult)
{
WebRequest request = (WebRequest)asynchronousResult.AsyncState;
Stream postStream = request.EndGetRequestStream(asynchronousResult);
string postData = String.Format(" ClientInfo = {0}", clientInfoStr);
try
{
using (StreamWriter writer = new StreamWriter(postStream))
{
writer.Write(postData);
writer.Flush();
}
}
catch (Exception ex)
{
string ke = ex.ToString();
}
向服务器端请求返回信息#region 向服务器端请求返回信息
//WebRequest类的一个特性就是可以异步请求页面。由于在给主机发送请求到接收响应之间有很长的延迟,因此,异步请求页面就显得比较重要。
//像WebClient.DownloadData()和WebRequest.GetResponse()等方法,在响应没有从服务器回来之前,是不会返回的。
//如果不希望在那段时间中应用程序处于等待状态,可以使用BeginGetResponse() 方法和 EndGetResponse()方法,
//BeginGetResponse()方法可以异步工作,并立即返回。在底层,运行库会异步管理一个后台线程,从服务器上接收响应。
//BeginGetResponse() 方法不返回WebResponse对象,而是返回一个执行IAsyncResult接口的对象。使用这个接口可以选择或等待可用的响应,然后调用EndGetResponse()搜集结果。
request.BeginGetResponse(new AsyncCallback(OnResponse), request);
#endregion
}
#endregion
接收服务器端的信息#region 接收服务器端的信息
protected void OnResponse(IAsyncResult ar)
{
WebRequest wrq = (WebRequest)ar.AsyncState;
//对应 BeginGetResponse()方法,在此处调用EndGetResponse()搜集结果。
//WebResponse类代表从服务器获取的数据。调用EndGetResponse方法,实际上是把请求发送给Web服务器,创建一个Response对象。
WebResponse wrs = wrq.EndGetResponse(ar);
// 读取WebResponse对象中内含的从服务器端返回的结果数据流
using (Stream responseStream = wrs.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream);
string retGet = reader.ReadToEnd();
serverInfoStr = retGet;
//通过Thread完成对UI的修改
//因为在多线程情况下,不能在背景线程里操作UI线程, 改为:
Thread mythread = new Thread(new ThreadStart(AcrossThread));
mythread.Start();
}
}
修改UI内容#region 修改UI内容
private void AcrossThread()
{
currentContext.Post(result =>
{
this.tbRetText.Text = serverInfoStr; //在此处修改UI内容
}, null);
}
#endregion
#endregion
}
}
3、服务器端完成的工作
在建立的Handler中接收客户端的信息,做相应处理后返回给客户端。
WebRequestHandler.ashx.cs全部代码如下:
using
System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SLWebRequestTest.Web
{
public class WebRequestHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// 读取从客户端传来的参数
// string clientInfoStr = context.Request.Params.Get("ClientInfo");
// string clientInfoStr = context.Request.Form["ClientInfo"];
string clientInfoStr = context.Request.Form[ 0 ];
// 返回信息
context.Response.ContentType = " text/plain " ;
context.Response.Write( " Server Received Client Info: " + clientInfoStr + " \n Server Return To Client: Welcome To Server " );
}
public bool IsReusable
{
get
{
return false ;
}
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SLWebRequestTest.Web
{
public class WebRequestHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// 读取从客户端传来的参数
// string clientInfoStr = context.Request.Params.Get("ClientInfo");
// string clientInfoStr = context.Request.Form["ClientInfo"];
string clientInfoStr = context.Request.Form[ 0 ];
// 返回信息
context.Response.ContentType = " text/plain " ;
context.Response.Write( " Server Received Client Info: " + clientInfoStr + " \n Server Return To Client: Welcome To Server " );
}
public bool IsReusable
{
get
{
return false ;
}
}
}
}
(转载本文请注明出处)