本文我們學習如何使用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 ;
}
}
}
}
(轉載本文請註明出處)