接上节,本文直接进入实例操作部分。在此处,我们以典型的图片文件为例来学习如何用WebClient类来实现上传和下载流数据的。
新建一个Silverlight应用程序,命名为:SLWebClientStream。
一、准备工作:
1、准备一张图片,本例我们准备了一张名为Bubble.jpg的图片,把它拷贝到SLWebClientStream.Web项目的根目录下。
2、在SLWebClientStream.Web项目下新建一个目录,命名为Pics,我们将在此处放置上传上来的图片文件。
完成准备工作后,项目如下图:
二、编码实现
(一)、客户端部分
1、建立用户界面
Page.xaml内容如下:
<
UserControl x:Class
=
"
SLWebClientStream.Page
"
xmlns
=
"
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x
=
"
http://schemas.microsoft.com/winfx/2006/xaml
"
Width
=
"
500
"
Height
=
"
450
"
>
<
StackPanel Background
=
"
White
"
Height
=
"
450
"
>
<
TextBlock x:Name
=
"
tbMsgString
"
Text
=
"
下载进度
"
TextAlignment
=
"
Center
"
Foreground
=
"
Green
"
></
TextBlock
>
<
Button x:Name
=
"
btnDownload
"
Content
=
"
DownLoad Pictures
"
Width
=
"
150
"
Height
=
"
35
"
Margin
=
"
15
"
Click
=
"
btnDownload_Click
"
/>
<
Border Background
=
"
Wheat
"
BorderThickness
=
"
5
"
Width
=
"
400
"
Height
=
"
280
"
>
<
Image x:Name
=
"
imgDownLoad
"
Width
=
"
400
"
Height
=
"
300
"
Margin
=
"
15
"
Stretch
=
"
Fill
"
/>
</
Border
>
<
Button x:Name
=
"
btnUpLoad
"
Content
=
"
UpLoad Pictures
"
Width
=
"
150
"
Height
=
"
35
"
Margin
=
"
15
"
Click
=
"
btnUpLoad_Click
"
/>
</
StackPanel
>
</
UserControl
>
界面如下:
2、下载图片文件代码
#region
下载图片
private
void
btnDownload_Click(
object
sender, RoutedEventArgs e)
{
//
向指定的Url发送下载流数据请求
String imgUrl
=
"
http://localhost:51896/Bubble.jpg
"
;
Uri endpoint
=
new
Uri(imgUrl);
WebClient client
=
new
WebClient();
client.OpenReadCompleted
+=
new
OpenReadCompletedEventHandler(OnOpenReadCompleted);
client.DownloadProgressChanged
+=
new
DownloadProgressChangedEventHandler(clientDownloadStream_DownloadProgressChanged);
client.OpenReadAsync(endpoint);
}
void
OnOpenReadCompleted(
object
sender,OpenReadCompletedEventArgs e)
{
//
OpenReadCompletedEventArgs.Error - 该异步操作期间是否发生了错误
//
OpenReadCompletedEventArgs.Cancelled - 该异步操作是否已被取消
//
OpenReadCompletedEventArgs.Result - 下载后的 Stream 类型的数据
//
OpenReadCompletedEventArgs.UserState - 用户标识
if
(e.Error
!=
null
)
{
MessageBox.Show(e.Error.ToString());
return
;
}
if
(e.Cancelled
!=
true
)
{
//
获取下载的流数据(在此处是图片数据)并显示在图片控件中
Stream stream
=
e.Result;
BitmapImage bitmap
=
new
BitmapImage();
bitmap.SetSource(stream);
imgDownLoad.Source
=
bitmap;
}
}
void
clientDownloadStream_DownloadProgressChanged(
object
sender, DownloadProgressChangedEventArgs e)
{
//
DownloadProgressChangedEventArgs.ProgressPercentage - 下载完成的百分比
//
DownloadProgressChangedEventArgs.BytesReceived - 当前收到的字节数
//
DownloadProgressChangedEventArgs.TotalBytesToReceive - 总共需要下载的字节数
//
DownloadProgressChangedEventArgs.UserState - 用户标识
this
.tbMsgString.Text
=
string
.Format(
"
完成百分比:{0} 当前收到的字节数:{1} 资料大小:{2}
"
,
e.ProgressPercentage.ToString()
+
"
%
"
,
e.BytesReceived.ToString(),
e.TotalBytesToReceive.ToString());
}
#endregion
3、上传图片文件代码
#region
上传图片
private
void
btnUpLoad_Click(
object
sender, RoutedEventArgs e)
{
/*
* OpenWriteCompleted - 在打开用于上传的流完成时(包括取消操作及有错误发生时)所触发的事件
* WriteStreamClosed - 在写入数据流的异步操作完成时(包括取消操作及有错误发生时)所触发的事件
* UploadProgressChanged - 上传数据过程中所触发的事件。如果调用 OpenWriteAsync() 则不会触发此事件
* Headers - 与请求相关的的标头的 key/value 对**
* OpenWriteAsync(Uri address, string method, Object userToken) - 打开流以使用指定的方法向指定的 URI 写入数据
* Uri address - 接收上传数据的 URI
* string method - 所使用的 HTTP 方法(POST 或 GET)
* Object userToken - 需要上传的数据流
*/
OpenFileDialog openFileDialog
=
new
OpenFileDialog()
{
//
弹出打开文件对话框要求用户自己选择在本地端打开的图片文件
Filter
=
"
Jpeg Files (*.jpg)|*.jpg|All Files(*.*)|*.*
"
,
Multiselect
=
false
//
不允许多选
};
if
(openFileDialog.ShowDialog()
==
true
)
//
.DialogResult.OK)
{
//
fileinfo = openFileDialog.Files;
//
取得所选择的文件,其中Name为文件名字段,作为绑定字段显示在前端
fileinfo
=
openFileDialog.File;
if
(fileinfo
!=
null
)
{
WebClient webclient
=
new
WebClient();
string
uploadFileName
=
fileinfo.Name.ToString();
//
获取所选文件的名字
#region
把图片上传到服务器上
Uri upTargetUri
=
new
Uri(String.Format(
"
http://localhost:51896/WebClientUpLoadStreamHandler.ashx?fileName={0}
"
, uploadFileName), UriKind.Absolute);
//
指定上传地址
webclient.OpenWriteCompleted
+=
new
OpenWriteCompletedEventHandler(webclient_OpenWriteCompleted);
webclient.Headers[
"
Content-Type
"
]
=
"
multipart/form-data
"
;
webclient.OpenWriteAsync(upTargetUri,
"
POST
"
, fileinfo.OpenRead());
webclient.WriteStreamClosed
+=
new
WriteStreamClosedEventHandler(webclient_WriteStreamClosed);
#endregion
}
else
{
MessageBox.Show(
"
请选取想要上载的图片!!!
"
);
}
}
}
void
webclient_OpenWriteCompleted(
object
sender, OpenWriteCompletedEventArgs e)
{
//
将图片数据流发送到服务器上
//
e.UserState - 需要上传的流(客户端流)
Stream clientStream
=
e.UserState
as
Stream;
//
e.Result - 目标地址的流(服务端流)
Stream serverStream
=
e.Result;
byte
[] buffer
=
new
byte
[
4096
];
int
readcount
=
0
;
//
clientStream.Read - 将需要上传的流读取到指定的字节数组中
while
((readcount
=
clientStream.Read(buffer,
0
, buffer.Length))
>
0
)
{
//
serverStream.Write - 将指定的字节数组写入到目标地址的流
serverStream.Write(buffer,
0
, readcount);
}
serverStream.Close();
clientStream.Close();
}
void
webclient_WriteStreamClosed(
object
sender, WriteStreamClosedEventArgs e)
{
//
判断写入是否有异常
if
(e.Error
!=
null
)
{
System.Windows.Browser.HtmlPage.Window.Alert(e.Error.Message.ToString());
}
else
{
System.Windows.Browser.HtmlPage.Window.Alert(
"
图片上传成功!!!
"
);
}
}
#endregion
Page.xaml.cs全部代码如下:
Code
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.Windows.Media.Imaging; //因为要使用BitmapImage
using System.IO; //因为要使用Stream
namespace SLWebClientStream
{
public partial class Page : UserControl
{
//1、WebClient 对象一次只能启动一个请求。如果在一个请求完成(包括出错和取消)前,即IsBusy为true时,进行第二个请求,则第二个请求将会抛出 NotSupportedException 类型的异常
//2、如果 WebClient 对象的 BaseAddress 属性不为空,则 BaseAddress 与 URI(相对地址) 组合在一起构成绝对 URI
//3、WebClient 类的 AllowReadStreamBuffering 属性:是否对从 Internet 资源接收的数据做缓冲处理。默认值为true,将数据缓存在客户端内存中,以便随时被应用程序读取
//获取选定图片信息
System.IO.FileInfo fileinfo;
public Page()
{
InitializeComponent();
}
下载图片#region 下载图片
private void btnDownload_Click(object sender, RoutedEventArgs e)
{
//向指定的Url发送下载流数据请求
String imgUrl = "http://localhost:51896/Bubble.jpg";
Uri endpoint = new Uri(imgUrl);
WebClient client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(OnOpenReadCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(clientDownloadStream_DownloadProgressChanged);
client.OpenReadAsync(endpoint);
}
void OnOpenReadCompleted(object sender,OpenReadCompletedEventArgs e)
{
//OpenReadCompletedEventArgs.Error - 该异步操作期间是否发生了错误
//OpenReadCompletedEventArgs.Cancelled - 该异步操作是否已被取消
//OpenReadCompletedEventArgs.Result - 下载后的 Stream 类型的数据
//OpenReadCompletedEventArgs.UserState - 用户标识
if (e.Error != null)
{
MessageBox.Show(e.Error.ToString());
return;
}
if (e.Cancelled != true)
{
//获取下载的流数据(在此处是图片数据)并显示在图片控件中
Stream stream = e.Result;
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(stream);
imgDownLoad.Source = bitmap;
}
}
void clientDownloadStream_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
//DownloadProgressChangedEventArgs.ProgressPercentage - 下载完成的百分比
//DownloadProgressChangedEventArgs.BytesReceived - 当前收到的字节数
//DownloadProgressChangedEventArgs.TotalBytesToReceive - 总共需要下载的字节数
//DownloadProgressChangedEventArgs.UserState - 用户标识
this.tbMsgString.Text = string.Format("完成百分比:{0} 当前收到的字节数:{1} 资料大小:{2} ",
e.ProgressPercentage.ToString() + "%",
e.BytesReceived.ToString(),
e.TotalBytesToReceive.ToString());
}
#endregion
上传图片#region 上传图片
private void btnUpLoad_Click(object sender, RoutedEventArgs e)
{
/**//*
* OpenWriteCompleted - 在打开用于上传的流完成时(包括取消操作及有错误发生时)所触发的事件
* WriteStreamClosed - 在写入数据流的异步操作完成时(包括取消操作及有错误发生时)所触发的事件
* UploadProgressChanged - 上传数据过程中所触发的事件。如果调用 OpenWriteAsync() 则不会触发此事件
* Headers - 与请求相关的的标头的 key/value 对**
* OpenWriteAsync(Uri address, string method, Object userToken) - 打开流以使用指定的方法向指定的 URI 写入数据
* Uri address - 接收上传数据的 URI
* string method - 所使用的 HTTP 方法(POST 或 GET)
* Object userToken - 需要上传的数据流
*/
OpenFileDialog openFileDialog = new OpenFileDialog()
{ //弹出打开文件对话框要求用户自己选择在本地端打开的图片文件
Filter = "Jpeg Files (*.jpg)|*.jpg|All Files(*.*)|*.*",
Multiselect = false //不允许多选
};
if (openFileDialog.ShowDialog() == true)//.DialogResult.OK)
{
//fileinfo = openFileDialog.Files; //取得所选择的文件,其中Name为文件名字段,作为绑定字段显示在前端
fileinfo=openFileDialog.File;
if (fileinfo != null)
{
WebClient webclient = new WebClient();
string uploadFileName = fileinfo.Name.ToString(); //获取所选文件的名字
把图片上传到服务器上#region 把图片上传到服务器上
Uri upTargetUri = new Uri(String.Format("http://localhost:51896/WebClientUpLoadStreamHandler.ashx?fileName={0}", uploadFileName), UriKind.Absolute); //指定上传地址
webclient.OpenWriteCompleted += new OpenWriteCompletedEventHandler(webclient_OpenWriteCompleted);
webclient.Headers["Content-Type"] = "multipart/form-data";
webclient.OpenWriteAsync(upTargetUri, "POST", fileinfo.OpenRead());
webclient.WriteStreamClosed += new WriteStreamClosedEventHandler(webclient_WriteStreamClosed);
#endregion
}
else
{
MessageBox.Show("请选取想要上载的图片!!!");
}
}
}
void webclient_OpenWriteCompleted(object sender, OpenWriteCompletedEventArgs e)
{
//将图片数据流发送到服务器上
// e.UserState - 需要上传的流(客户端流)
Stream clientStream = e.UserState as Stream;
// e.Result - 目标地址的流(服务端流)
Stream serverStream = e.Result;
byte[] buffer = new byte[4096];
int readcount = 0;
// clientStream.Read - 将需要上传的流读取到指定的字节数组中
while ((readcount = clientStream.Read(buffer, 0, buffer.Length)) > 0)
{
// serverStream.Write - 将指定的字节数组写入到目标地址的流
serverStream.Write(buffer, 0, readcount);
}
serverStream.Close();
clientStream.Close();
}
void webclient_WriteStreamClosed(object sender, WriteStreamClosedEventArgs e)
{
//判断写入是否有异常
if (e.Error != null)
{
System.Windows.Browser.HtmlPage.Window.Alert(e.Error.Message.ToString());
}
else
{
System.Windows.Browser.HtmlPage.Window.Alert("图片上传成功!!!");
}
}
#endregion
}
}
(二)、服务器端部分
编写配合上传图片处理的Handler,我们命名为WebClientUpLoadStreamHandler.ashx,代码如下:
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.IO;
//
因为要用到Stream
namespace
SLWebClientStream.Web
{
public
class
WebClientUpLoadStreamHandler : IHttpHandler
{
public
void
ProcessRequest(HttpContext context)
{
//
获取上传的数据流
string
fileNameStr
=
context.Request.QueryString[
"
fileName
"
];
Stream sr
=
context.Request.InputStream;
try
{
string
filename
=
""
;
filename
=
fileNameStr;
byte
[] buffer
=
new
byte
[
4096
];
int
bytesRead
=
0
;
//
将当前数据流写入服务器端文件夹ClientBin下
string
targetPath
=
context.Server.MapPath(
"
Pics/
"
+
filename
+
"
.jpg
"
);
using
(FileStream fs
=
File.Create(targetPath,
4096
))
{
while
((bytesRead
=
sr.Read(buffer,
0
, buffer.Length))
>
0
)
{
//
向文件中写信息
fs.Write(buffer,
0
, bytesRead);
}
}
context.Response.ContentType
=
"
text/plain
"
;
context.Response.Write(
"
上传成功
"
);
}
catch
(Exception e)
{
context.Response.ContentType
=
"
text/plain
"
;
context.Response.Write(
"
上传失败, 错误信息:
"
+
e.Message);
}
finally
{ sr.Dispose(); }
}
public
bool
IsReusable
{
get
{
return
false
;
}
}
}
}
完成上述工作后,生成项目,运行后效果如下:
上传图片后,所上传图处在如下位置
前往:Silverlight学习笔记清单
本文程序在Silverlight2.0和VS2008环境中调试通过。本文参照了部分网络资料,希望能够抛砖引玉,大家共同学习。
(转载本文请注明出处)