隨著internet技術(shù)的發(fā)展和跨平臺(tái)需求的日益增加,web services的應(yīng)用越來(lái)越廣,我們不但需要通過(guò)web services傳遞字符串信息,而且需要傳遞二進(jìn)制文件信息。下面,我們就分別介紹如何通過(guò)web services從服務(wù)器下載文件到客戶端和從客戶端通過(guò)web services上載文件到服務(wù)器。
一:通過(guò)web services顯示和下載文件
我們這里建立的web services的名稱為getbinaryfile,提供兩個(gè)公共方法:分別是getimage()和getimagetype(),前者返回二進(jìn)制文件字節(jié)數(shù)組,后者返回文件類型,其中,getimage()方法有一個(gè)參數(shù),用來(lái)在客戶端選擇要顯示或下載的文件名字。這里我們所顯示和下載的文件可以不在虛擬目錄下,采用這個(gè)方法的好處是:可以根據(jù)權(quán)限對(duì)文件進(jìn)行顯示和下載控制,從下面的方法我們可以看出,實(shí)際的文件位置并沒(méi)有在虛擬目錄下,因此可以更好地對(duì)文件進(jìn)行權(quán)限控制,這在對(duì)安全性有比較高的情況下特別有用。這個(gè)功能在以前的asp程序中可以用stream對(duì)象實(shí)現(xiàn)。為了方便讀者進(jìn)行測(cè)試,這里列出了全部的源代碼,并在源代碼里進(jìn)行介紹和注釋。
首先,建立getbinaryfile.asmx文件:
我們可以在vs.net里新建一個(gè)c#的aspxwebcs工程,然后“添加新項(xiàng)”,選擇“web服務(wù)”,并設(shè)定文件名為:getbinaryfile.asmx,在“查看代碼”中輸入以下代碼,即:getbinaryfile.asmx.cs:
using system;
using system.collections;
using system.componentmodel;
using system.data;
using system.diagnostics;
using system.web;
using system.web.ui;
using system.web.services;
using system.io;
namespace xml.sz.luohuedu.net.aspxwebcs
{
/// <summary>
/// getbinaryfile 的摘要說(shuō)明。
/// web services名稱:getbinaryfile
/// 功能:返回服務(wù)器上的一個(gè)文件對(duì)象的二進(jìn)制字節(jié)數(shù)組。
/// </summary>
[webservice(namespace="http://xml.sz.luohuedu.net/",
description="在web services里利用.net框架進(jìn)行傳遞二進(jìn)制文件。")]
public class getbinaryfile : system.web.services.webservice
{
#region component designer generated code
//web 服務(wù)設(shè)計(jì)器所必需的
private icontainer components = null;
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void dispose( bool disposing )
{
if(disposing && components != null)
{
components.dispose();
}
base.dispose(disposing);
}
#endregion
public class images: system.web.services.webservice
{
/// <summary>
/// web 服務(wù)提供的方法,返回給定文件的字節(jié)數(shù)組。
/// </summary>
[webmethod(description="web 服務(wù)提供的方法,返回給定文件的字節(jié)數(shù)組")]
public byte[] getimage(string requestfilename)
{
///得到服務(wù)器端的一個(gè)圖片
///如果你自己測(cè)試,注意修改下面的實(shí)際物理路徑
if(requestfilename == null || requestfilename == "")
return getbinaryfile("d://picture.jpg");
else
return getbinaryfile("d://" + requestfilename);
}
/// <summary>
/// getbinaryfile:返回所給文件路徑的字節(jié)數(shù)組。
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public byte[] getbinaryfile(string filename)
{
if(file.exists(filename))
{
try
{
///打開(kāi)現(xiàn)有文件以進(jìn)行讀取。
filestream s = file.openread(filename);
return convertstreamtobytebuffer(s);
}
catch(exception e)
{
return new byte[0];
}
}
else
{
return new byte[0];
}
}
/// <summary>
/// convertstreamtobytebuffer:把給定的文件流轉(zhuǎn)換為二進(jìn)制字節(jié)數(shù)組。
/// </summary>
/// <param name="thestream"></param>
/// <returns></returns>
public byte[] convertstreamtobytebuffer(system.io.stream thestream)
{
int b1;
system.io.memorystream tempstream = new system.io.memorystream();
while((b1=thestream.readbyte())!=-1)
{
tempstream.writebyte(((byte)b1));
}
return tempstream.toarray();
}
[webmethod(description="web 服務(wù)提供的方法,返回給定文件類型。")]
public string getimagetype()
{
///這里只是測(cè)試,您可以根據(jù)實(shí)際的文件類型進(jìn)行動(dòng)態(tài)輸出
return "image/jpg";
}
}
}
}
一旦我們創(chuàng)建了上面的asmx文件,進(jìn)行編譯后,我們就可以編寫(xiě)客戶端的代碼來(lái)進(jìn)行調(diào)用這個(gè)web services了。
我們先“添加web引用”,輸入:http://localhost/aspxwebcs/getbinaryfile.asmx。下面,我們編寫(xiě)顯示文件的中間文件:getbinaryfileshow.aspx,這里,我們只需要在后代碼里編寫(xiě)代碼即可,getbinaryfileshow.aspx.cs文件內(nèi)容如下:
using system;
using system.collections;
using system.componentmodel;
using system.data;
using system.drawing;
using system.web;
using system.web.sessionstate;
using system.web.ui;
using system.web.ui.webcontrols;
using system.web.ui.htmlcontrols;
using system.web.services;
namespace aspxwebcs
{
/// <summary>
/// getbinaryfileshow 的摘要說(shuō)明。
/// </summary>
public class getbinaryfileshow : system.web.ui.page
{
private void page_load(object sender, system.eventargs e)
{
// 在此處放置用戶代碼以初始化頁(yè)面
///定義并初始化文件對(duì)象;
xml.sz.luohuedu.net.aspxwebcs.getbinaryfile.images oimage;
oimage = new xml.sz.luohuedu.net.aspxwebcs.getbinaryfile.images();
///得到二進(jìn)制文件字節(jié)數(shù)組;
byte[] image = oimage.getimage("");
///轉(zhuǎn)換為支持存儲(chǔ)區(qū)為內(nèi)存的流
system.io.memorystream memstream = new system.io.memorystream(image);
///定義并實(shí)例化bitmap對(duì)象
bitmap bm = new bitmap(memstream);
///根據(jù)不同的條件進(jìn)行輸出或者下載;
response.clear();
///如果請(qǐng)求字符串指定下載,就下載該文件;
///否則,就顯示在瀏覽器中。
if(request.querystring["download"]=="1")
{
response.buffer = true;
response.contenttype = "application/octet-stream";
///這里下載輸出的文件名字 ok.jpg 為例子,你實(shí)際中可以根據(jù)情況動(dòng)態(tài)決定。
response.addheader("content-disposition","attachment;filename=ok.jpg");
}
else
response.contenttype = oimage.getimagetype();
response.binarywrite(image);
response.end();
}
#region web form designer generated code
override protected void oninit(eventargs e)
{
//
// codegen:該調(diào)用是 asp.net web 窗體設(shè)計(jì)器所必需的。
//
initializecomponent();
base.oninit(e);
}
/// <summary>
/// 設(shè)計(jì)器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內(nèi)容。
/// </summary>
private void initializecomponent()
{
this.load += new system.eventhandler(this.page_load);
}
#endregion
}
}
最后,我們就編寫(xiě)最終的瀏覽頁(yè)面:getbinaryfile.aspx,這個(gè)文件很簡(jiǎn)單,只需要aspx文件即可,內(nèi)容如下:
<%@ page language="c#" codebehind="getbinaryfile.aspx.cs" autoeventwireup="false"
inherits="aspxwebcs.getbinaryfile" %>
<!doctype html public "-//w3c//dtd html 4.0 transitional//en" >
<html>
<head>
<title>通過(guò)web services顯示和下載文件</title>
<meta name="generator" content="microsoft visual studio 7.0">
<meta name="code_language" content="c#">
<meta name="vs_defaultclientscript" content="javascript">
<meta name="vs_targetschema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body ms_positioning="gridlayout">
<form id="getbinaryfile" method="post" runat="server">
<font face="宋體">
<asp:hyperlink id="hyperlink1" navigateurl="getbinaryfileshow.aspx?download=1"
runat="server">下載文件</asp:hyperlink>
<br/>
<!--下面是直接顯示文件-->
<asp:image id="image1" imageurl="getbinaryfileshow.aspx" runat="server"></asp:image>
</font>
</form>
</body>
</html>
二:通過(guò)web services上載文件
向服務(wù)器上載文件可能有許多種方法,在利用web services上載文件的方法中,下面的這個(gè)方法應(yīng)該是最簡(jiǎn)單的了。我們?nèi)韵笄懊娴睦幽菢樱紫冉pload.asmx文件,其upload.asmx.cs內(nèi)容如下,里面已經(jīng)做了注釋:
using system;
using system.collections;
using system.componentmodel;
using system.data;
using system.diagnostics;
using system.web;
using system.web.services;
using system.io;
namespace xml.sz.luohuedu.net.aspxwebcs
{
/// <summary>
/// upload 的摘要說(shuō)明。
/// </summary>
[webservice(namespace="http://xml.sz.luohuedu.net/",
description="在web services里利用.net框架進(jìn)上載文件。")]
public class upload : system.web.services.webservice
{
public upload()
{
//codegen:該調(diào)用是 asp.net web 服務(wù)設(shè)計(jì)器所必需的
initializecomponent();
}
#region component designer generated code
//web 服務(wù)設(shè)計(jì)器所必需的
private icontainer components = null;
/// <summary>
/// 設(shè)計(jì)器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內(nèi)容。
/// </summary>
private void initializecomponent()
{
}
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void dispose( bool disposing )
{
if(disposing && components != null)
{
components.dispose();
}
base.dispose(disposing);
}
#endregion
[webmethod(description="web 服務(wù)提供的方法,返回是否文件上載成功與否。")]
public string uploadfile(byte[] fs,string filename)
{
try
{
///定義并實(shí)例化一個(gè)內(nèi)存流,以存放提交上來(lái)的字節(jié)數(shù)組。
memorystream m = new memorystream(fs);
///定義實(shí)際文件對(duì)象,保存上載的文件。
filestream f = new filestream(server.mappath(".") + "http://"
+ filename, filemode.create);
///把內(nèi)內(nèi)存里的數(shù)據(jù)寫(xiě)入物理文件
m.writeto(f);
m.close();
f.close();
f = null;
m = null;
return "文件已經(jīng)上傳成功。";
}
catch(exception ex)
{
return ex.message;
}
}
}
}
要上載文件,必須提供一個(gè)表單,來(lái)供用戶進(jìn)行文件的選擇,下面我們就建立這樣一個(gè)頁(yè)面upload.aspx,用來(lái)提供文件上載:
<%@ page language="c#" codebehind="upload.aspx.cs" autoeventwireup="false"
inherits="aspxwebcs.upload" %>
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<title>通過(guò)web services上載文件</title>
<meta name="generator" content="microsoft visual studio .net 7.0">
<meta name="code_language" content="visual basic 7.0">
<meta name="vs_defaultclientscript" content="javascript">
<meta name="vs_targetschema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body ms_positioning="gridlayout">
<form id="form1" method="post" runat="server" enctype="multipart/form-data">
<input id="myfile" type="file" runat="server">
<br>
<br>
<asp:button id="button1" runat="server" text="上載文件"></asp:button>
</form>
</body>
</html>
我們要進(jìn)行處理的是在后代碼里面,下面詳細(xì)的介紹,upload.aspx.cs:
using system;
using system.collections;
using system.componentmodel;
using system.data;
using system.drawing;
using system.web;
using system.web.sessionstate;
using system.web.ui;
using system.web.ui.webcontrols;
using system.web.ui.htmlcontrols;
using system.web.services;
using system.io;
namespace aspxwebcs
{
/// <summary>
/// upload 的摘要說(shuō)明。
/// 利用該方法通過(guò)web services上載文件
/// </summary>
public class upload : system.web.ui.page
{
protected system.web.ui.htmlcontrols.htmlinputfile myfile;
protected system.web.ui.webcontrols.button button1;
private void page_load(object sender, system.eventargs e)
{
// 在此處放置用戶代碼以初始化頁(yè)面
}
#region web form designer generated code
override protected void oninit(eventargs e)
{
//
// codegen:該調(diào)用是 asp.net web 窗體設(shè)計(jì)器所必需的。
//
initializecomponent();
base.oninit(e);
}
/// <summary>
/// 設(shè)計(jì)器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內(nèi)容。
/// </summary>
private void initializecomponent()
{
this.button1.click += new system.eventhandler(this.button1_click);
this.load += new system.eventhandler(this.page_load);
}
#endregion
private void button1_click(object sender, system.eventargs e)
{
///首先得到上載文件信息和文件流
if(myfile.postedfile != null)
{
system.web.httpfilecollection ofiles;
ofiles = system.web.httpcontext.current.request.files;
if(ofiles.count < 1)
{
response.write ("請(qǐng)選擇文件。");
response.end();
}
string filepath = ofiles[0].filename;
if(filepath == "" || filepath == null)
{
response.write ("請(qǐng)選擇一個(gè)文件。");
response.end();
}
string filename = filepath.substring(filepath.lastindexof("http://")+1);
try
{
///處理上載的文件流信息。
byte[] b = new byte[ofiles[0].contentlength];
system.io.stream fs;
xml.sz.luohuedu.net.aspxwebcs.upload o;
o = new xml.sz.luohuedu.net.aspxwebcs.upload();
fs = (system.io.stream)ofiles[0].inputstream;
fs.read(b, 0, ofiles[0].contentlength);
///調(diào)用web services的uploadfile方法進(jìn)行上載文件。
response.write(o.uploadfile(b, filename));
fs.close();
}
catch(exception ex)
{
response.write(ex.message);
}
}
else
{
response.write("請(qǐng)選擇文件");
}
}
}
}
最后,需要注意的是:在保存文件時(shí),您應(yīng)該確保指定文件的完整路徑(例如,"c:/myfiles/picture.jpg"),并確保為 asp.net 使用的帳戶提供要存儲(chǔ)文件的目錄的寫(xiě)權(quán)限。上載大文件時(shí),可使用 元素的 maxrequestlength 屬性來(lái)增加文件大小的最大允許值,例如:
<configuration>
<system.web>
<httpruntime maxrequestlength="1048576" executiontimeout="3600" />
</system.web>
</configuration>
其中:maxrequestlength:指示 asp.net 支持的http方式上載的最大字節(jié)數(shù)。該限制可用于防止因用戶將大量文件傳遞到該服務(wù)器而導(dǎo)致的拒絕服務(wù)攻擊。指定的大小以 kb 為單位。默認(rèn)值為 4096 kb (4 mb)。executiontimeout:指示在被 asp.net 自動(dòng)關(guān)閉前,允許執(zhí)行請(qǐng)求的最大秒數(shù)。在當(dāng)文件超出指定的大小時(shí),如果瀏覽器中會(huì)產(chǎn)生 dns 錯(cuò)誤或者出現(xiàn)服務(wù)不可得到的情況,也請(qǐng)修改以上的配置,把配置數(shù)加大。
另外,上載大文件時(shí),還可能會(huì)收到以下錯(cuò)誤信息:
aspnet_wp.exe (pid: 1520) 被回收,因?yàn)閮?nèi)存消耗超過(guò)了 460 mb(可用 ram 的百分之 60)。
如果遇到此錯(cuò)誤信息,請(qǐng)?jiān)黾討?yīng)用程序的 web.config 文件的 元素中 memorylimit 屬性的值。例如:
<configuration>
<system.web>
<processmodel memorylimit="80"/>
</system.web>
</configuration>
我在自己的機(jī)器上測(cè)試,可以上傳50m以上的文件。以上代碼在windows xp + .net 1.0 + vs.net2002下測(cè)試通過(guò)。
|
新聞熱點(diǎn)
疑難解答
圖片精選