通過Web Services上傳和下載檔案
隨著Internet技術的發展和跨平臺需求的日益增加,Web Services的應用越來越廣,我們不但需要通過Web Services傳遞字串資訊,而且需要傳遞二進位制檔案資訊。下面,我們就分別介紹如何通過Web Services從伺服器下載檔案到客戶端和從客戶端通過Web Services上載檔案到伺服器。
一:通過Web Services顯示和下載檔案
我們這裡建立的Web Services的名稱為GetBinaryFile,提供兩個公共方法:分別是GetImage()和GetImageType(),前者返回二進位制檔案位元組陣列,後者返回檔案型別,其中,GetImage()方法有一個引數,用來在客戶端選擇要顯示或下載的檔名字。這裡我們所顯示和下載的檔案可以不在虛擬目錄下,採用這個方法的好處是:可以根據許可權對檔案進行顯示和下載控制,從下面的方法我們可以看出,實際的檔案位置並沒有在虛擬目錄下,因此可以更好地對檔案進行許可權控制,這在對安全性有比較高的情況下特別有用。這個功能在以前的ASP程式中可以用Stream物件實現。為了方便讀者進行測試,這裡列出了全部的原始碼,並在原始碼裡進行介紹和註釋。
首先,建立GetBinaryFile.asmx檔案:
我們可以在VS.NET裡新建一個C#的aspxWebCS工程,然後“新增新項”,選擇“Web服務”,並設定檔名為: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 的摘要說明。
/// Web Services名稱:GetBinaryFile
/// 功能:返回伺服器上的一個檔案物件的二進位制位元組陣列。
/// </summary>
[WebService(Namespace="http://xml.sz.luohuedu.net/",
Description="在Web Services裡利用.NET框架進行傳遞二進位制檔案。")]
public class GetBinaryFile : System.Web.Services.WebService
{
#region Component Designer generated code
//Web 服務設計器所必需的
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 服務提供的方法,返回給定檔案的位元組陣列。
/// </summary>
[WebMethod(Description="Web 服務提供的方法,返回給定檔案的位元組陣列")]
public byte[] GetImage(string requestFileName)
{
///得到伺服器端的一個圖片
///如果你自己測試,注意修改下面的實際物理路徑
if(requestFileName == null || requestFileName == "")
return getBinaryFile("D://Picture.JPG");
else
return getBinaryFile("D://" + requestFileName);
}
/// <summary>
/// getBinaryFile:返回所給檔案路徑的位元組陣列。
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public byte[] getBinaryFile(string filename)
{
if(File.Exists(filename))
{
try
{
///開啟現有檔案以進行讀取。
FileStream s = File.OpenRead(filename);
return ConvertStreamToByteBuffer(s);
}
catch(Exception e)
{
return new byte[0];
}
}
else
{
return new byte[0];
}
}
/// <summary>
/// ConvertStreamToByteBuffer:把給定的檔案流轉換為二進位制位元組陣列。
/// </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 服務提供的方法,返回給定檔案型別。")]
public string GetImageType()
{
///這裡只是測試,您可以根據實際的檔案型別進行動態輸出
return "image/jpg";
}
}
}
}
一旦我們建立了上面的asmx檔案,進行編譯後,我們就可以編寫客戶端的程式碼來進行呼叫這個Web Services了。
我們先“新增Web引用”,輸入:http://localhost/aspxWebCS/GetBinaryFile.asmx。下面,我們編寫顯示檔案的中間檔案:GetBinaryFileShow.aspx,這裡,我們只需要在後程式碼裡編寫程式碼即可,GetBinaryFileShow.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;
namespace aspxWebCS
{
/// <summary>
/// GetBinaryFileShow 的摘要說明。
/// </summary>
public class GetBinaryFileShow : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
// 在此處放置使用者程式碼以初始化頁面
///定義並初始化檔案物件;
xml.sz.luohuedu.net.aspxWebCS.GetBinaryFile.Images oImage;
oImage = new xml.sz.luohuedu.net.aspxWebCS.GetBinaryFile.Images();
///得到二進位制檔案位元組陣列;
byte[] image = oImage.GetImage("");
///轉換為支援儲存區為記憶體的流
System.IO.MemoryStream memStream = new System.IO.MemoryStream(image);
///定義並例項化Bitmap物件
Bitmap bm = new Bitmap(memStream);
///根據不同的條件進行輸出或者下載;
Response.Clear();
///如果請求字串指定下載,就下載該檔案;
///否則,就顯示在瀏覽器中。
if(Request.QueryString["Download"]=="1")
{
Response.Buffer = true;
Response.ContentType = "application/octet-stream";
///這裡下載輸出的檔名字 ok.jpg 為例子,你實際中可以根據情況動態決定。
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:該呼叫是 ASP.NET Web 窗體設計器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 設計器支援所需的方法 - 不要使用程式碼編輯器修改
/// 此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
最後,我們就編寫最終的瀏覽頁面:GetBinaryFile.aspx,這個檔案很簡單,只需要aspx檔案即可,內容如下:
<%@ 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>通過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>
二:通過Web Services上載檔案
向伺服器上載檔案可能有許多種方法,在利用Web Services上載檔案的方法中,下面的這個方法應該是最簡單的了。我們仍象前面的例子那樣,首先建立Upload.asmx檔案,其Upload.asmx.cs內容如下,裡面已經做了註釋:
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 的摘要說明。
/// </summary>
[WebService(Namespace="http://xml.sz.luohuedu.net/",
Description="在Web Services裡利用.NET框架進上載檔案。")]
public class Upload : System.Web.Services.WebService
{
public Upload()
{
//CODEGEN:該呼叫是 ASP.NET Web 服務設計器所必需的
InitializeComponent();
}
#region Component Designer generated code
//Web 服務設計器所必需的
private IContainer components = null;
/// <summary>
/// 設計器支援所需的方法 - 不要使用程式碼編輯器修改
/// 此方法的內容。
/// </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 服務提供的方法,返回是否檔案上載成功與否。")]
public string UploadFile(byte[] fs,string FileName)
{
try
{
///定義並例項化一個記憶體流,以存放提交上來的位元組陣列。
MemoryStream m = new MemoryStream(fs);
///定義實際檔案物件,儲存上載的檔案。
FileStream f = new FileStream(Server.MapPath(".") + "//"
+ FileName, FileMode.Create);
///把內記憶體裡的資料寫入物理檔案
m.WriteTo(f);
m.Close();
f.Close();
f = null;
m = null;
return "檔案已經上傳成功。";
}
catch(Exception ex)
{
return ex.Message;
}
}
}
}
要上載檔案,必須提供一個表單,來供使用者進行檔案的選擇,下面我們就建立這樣一個頁面Upload.aspx,用來提供檔案上載:
<%@ 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>通過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>
我們要進行處理的是在後程式碼裡面,下面詳細的介紹,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 的摘要說明。
/// 利用該方法通過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)
{
// 在此處放置使用者程式碼以初始化頁面
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN:該呼叫是 ASP.NET Web 窗體設計器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 設計器支援所需的方法 - 不要使用程式碼編輯器修改
/// 此方法的內容。
/// </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 ("請選擇檔案。");
Response.End();
}
string FilePath = oFiles[0].FileName;
if(FilePath == "" || FilePath == null)
{
Response.Write ("請選擇一個檔案。");
Response.End();
}
string FileName = FilePath.Substring(FilePath.LastIndexOf("//")+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);
///呼叫Web Services的UploadFile方法進行上載檔案。
Response.Write(o.UploadFile(b, FileName));
fs.Close();
}
catch(Exception ex)
{
Response.Write(ex.Message);
}
}
else
{
Response.Write("請選擇檔案");
}
}
}
}
最後,需要注意的是:在儲存檔案時,您應該確保指定檔案的完整路徑(例如,"C:/MyFiles/Picture.jpg"),並確保為 ASP.NET 使用的帳戶提供要儲存檔案的目錄的寫許可權。上載大檔案時,可使用 元素的 maxRequestLength 屬性來增加檔案大小的最大允許值,例如:
<configuration>
<system.web>
<httpRuntime maxRequestLength="1048576" executionTimeout="3600" />
</system.web>
</configuration>
其中:maxRequestLength:指示 ASP.NET 支援的HTTP方式上載的最大位元組數。該限制可用於防止因使用者將大量檔案傳遞到該伺服器而導致的拒絕服務攻擊。指定的大小以 KB 為單位。預設值為 4096 KB (4 MB)。executionTimeout:指示在被 ASP.NET 自動關閉前,允許執行請求的最大秒數。在當檔案超出指定的大小時,如果瀏覽器中會產生 DNS 錯誤或者出現服務不可得到的情況,也請修改以上的配置,把配置數加大。
另外,上載大檔案時,還可能會收到以下錯誤資訊:
aspnet_wp.exe (PID: 1520) 被回收,因為記憶體消耗超過了 460 MB(可用 RAM 的百分之 60)。
如果遇到此錯誤資訊,請增加應用程式的 Web.config 檔案的 元素中 memoryLimit 屬性的值。例如:
<configuration>
<system.web>
<processModel memoryLimit="80"/>
</system.web>
</configuration>
我在自己的機器上測試,可以上傳50M以上的檔案。以上程式碼在Windows XP + .NET 1.0 + VS.NET2002下測試通過。