<C#高级编程>第31章笔记(上)
第31章的内容是访问Internet,本文作关于WebClient、WebRequest和WebResponse获取Web资源的笔记。
贴个图,本章的例子,以下是Form及对应的控件名,实现输入URL后获得页面内容:
第31章 访问Internet
先贴贴前文中的代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Net; using System.IO; namespace TestWebClient { public partial class WebClientForm : Form { public WebClientForm() { InitializeComponent(); } private void button_Click(object sender, EventArgs e) { // 清空文本框 content.Clear(); // 创建WebClient对象 WebClient client = new WebClient(); // 创建流引用 Stream stream = null; // 创建流读取对象引用 StreamReader reader = null; try { // 获得输入流 stream = client.OpenRead(url.Text); // 获得输入流读取对象 reader = new StreamReader(stream); // 读取数据并追加到文本框末尾 string line; while ((line = reader.ReadLine()) != null) { content.AppendText(line + "\n"); } } catch (Exception ex) { // 遇到Exception,提示错误信息 content.Text = ex.ToString(); } finally { // 关闭输入流读取对象 if (reader != null) { reader.Close(); } // 关闭输入流 if (stream != null) { stream.Close(); } // 释放WebClient资源 client.Dispose(); } } } }
WebClient具备了包括检索数据(OpenRead()方法)、写数据(OpenWrite()方法)、下载文件数据(DownloadFile()、DownloadData()方法)、上传文件数据(UploadFile()、UploadData()方法)等基本功能,
但是由于它是通用的,功能非常有限,不能处理任一协议的任何附加特性,例如HTTP协议中的Cookie。
此时我们通常用System.Net命名空间中以WebRequest类和WebResponse类为基类的一系列类。
例如对于HTTP协议,就可以使用HttpWebRequest和HttpWebResponse类。
另外,WebRequest有一个属性Credentials,可以将身份验证证书(NetworkCredential)附带在请求中。
下面是修改button_Click()方法,改用WebRequest和WebResponse实现的一个例子:
private void button_Click(object sender, EventArgs e) { // 清空文本框 content.Clear(); // 创建WebRequest对象引用 WebRequest request = null; // 创建WebResponse对象引用 WebResponse response = null; // 创建流引用 Stream stream = null; // 创建流读取对象引用 StreamReader reader = null; try { // 创建请求 request = WebRequest.Create(url.Text); // 获得回应 response = request.GetResponse(); // 获得输入流 stream = response.GetResponseStream(); // 获得输入流读取对象 reader = new StreamReader(stream); // 读取数据并追加到文本框末尾 string line; while ((line = reader.ReadLine()) != null) { content.AppendText(line + "\n"); } } catch (Exception ex) { // 遇到Exception,提示错误信息 content.Text = ex.ToString(); } finally { // 关闭输入流读取对象 if (reader != null) { reader.Close(); } // 关闭输入流 if (stream != null) { stream.Close(); } // 关闭WebResponse if (response != null) { response.Close(); } // 关闭WebRequest if (request != null) { request.Abort(); } } }
WebRequest类的另一个特性就是可以异步请求页面,通过BeginGetResponse()和EndGetResponse()方法。
BeginGetResponse()方法执行时管理一个后台进程,并返回IAsyncResult接口,
再通过EndGetResponse()方法获得结果。
* 注意,由于两个并非同一线程,修改控件值时VS会警告,这里参考了MSDN里面的样例代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
namespace TestWebClient
{
public partial class AsynForm : Form
{
// 委托
delegate void ChangeContentCallback(string text);
public AsynForm()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
// 清空文本框
content.Clear();
// 创建请求
WebRequest request = WebRequest.Create(url.Text);
// 开始异步接收
request.BeginGetResponse(new AsyncCallback(OnResponse), request);
}
// 回调方法
protected void OnResponse(IAsyncResult ar)
{
// 创建请求对象引用
WebRequest request = null;
// 创建回应对象引用
WebResponse response = null;
// 创建流引用
Stream stream = null;
// 创建输入流读取对象引用
StreamReader reader = null;
try
{
// 获得请求对象
request = (WebRequest)ar.AsyncState;
// 获得回应
response = request.EndGetResponse(ar);
// 获得输入流
stream = response.GetResponseStream();
// 获得输入流读取对象
reader = new StreamReader(stream);
// 读取数据并追加到文本框末尾
string line;
while ((line = reader.ReadLine()) != null)
{
this.AppendContent(line + "\n");
}
}
catch (Exception ex)
{
// 遇到Exception,提示错误信息
this.SetContent(ex.ToString());
}
finally
{
// 关闭输入流读取对象
if (reader != null)
{
reader.Close();
}
// 关闭输入流
if (stream != null)
{
stream.Close();
}
// 关闭WebResponse
if (response != null)
{
response.Close();
}
// 关闭WebRequest
if (request != null)
{
request.Abort();
}
}
}
// 对 Windows 窗体控件进行线程安全调用
private void SetContent(string text)
{
if (this.content.InvokeRequired)
{
ChangeContentCallback d = new ChangeContentCallback(SetContent);
this.Invoke(d, new object[] { text });
}
else
{
this.content.Text = text;
}
}
// 对 Windows 窗体控件进行线程安全调用
private void AppendContent(string text)
{
if (this.content.InvokeRequired)
{
ChangeContentCallback d = new ChangeContentCallback(AppendContent);
this.Invoke(d, new object[] { text });
}
else
{
this.content.AppendText(text);
}
}
}
}
既然都是M$家的,就可以考虑是否将网页内容以浏览器显示。
书上给出了两种办法:
第一种是通过调用IE,打开浏览器窗口显示Web页面:
Process process = new Process();
process.StartInfo.FileName = "iexplore.exe";
process.StartInfo.Arguments = url.Text;
process.Start();
第二种是通过工具箱里的浏览器控件,这样就可以将浏览器嵌入应用程序中操作:
byte[] postDatas = new byte[0]; string emptyString = ""; object oEmptyString = emptyString; browser.Navigate( url.Text, // URL字符串 emptyString, // 显示资源的目标帧(如果有) postDatas, // POST数据 emptyString // HTTP标题信息 );
也许是版本问题,书上的Navigate方法有5个参数,在VS 2005里最多只有4个参数。