asp.net下實現支援檔案分塊多點非同步上傳的 Web Services

來源:互聯網
上載者:User

本文的用戶端應用程式不包括 ASP.Net Web 應用程式!

本文假設 URL: http://localhost/mywebservices/updownload.asmx

共有 4 個程式檔案 (Web.Config 就不贅述了)

Server Side:

標題中所提到的 "非同步" 其實在伺服器端的程式並沒有什麼特殊的,而主要是通過用戶端應用程式
非同步呼叫相關 Web Method 實現的!

1. updownload.asmx ,位於 IIS 的某個 Web 共用目錄,代碼如下,只有一句話:

<%@ WebService Language="c#" Codebehind="UpDownLoad.asmx.cs" Class="Service1" %>

2. updownload.asmx.cs ,即: updownload.asmx 的 Codebehind ,位於 IIS 的某個 Web 共用目錄的 bin 子目錄下,代碼如下:

/*

本檔案位於 Web 共用目錄的 bin 子目錄下,通過執行如下命令列編譯:
csc /t:library updownload.asmx.cs

*/
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.IO;
using System;

public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}

//從 Web Method 本身,其實看不出 "同步" 還是 "非同步"
[WebMethod(Description = "為了支援多點分塊非同步上傳檔案,此方法必須由用戶端預先調用,以便在伺服器端產生指定 FileName 和 Length 大小的空白檔案預定空間! 建議用戶端同步調用")]
public string CreateBlankFile(string FileName,int Length) //建議由用戶端同步調用
{
FileStream fs = new FileStream(Server.MapPath(".") + "\\" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
fs.Write(new byte[Length], 0, Length);
fs.Close();
fs = null;
return FileName + " (" + Length + ") 空白檔案已經建立!";
}

[WebMethod(Description = "提供一個用於一次完整上傳整個檔案的方法! 建議用戶端同步調用")]
public string UploadFileBytes(byte[] Bytes,string FileName)
{
return UploadFileChunkBytes(Bytes, 0, FileName);
}

[WebMethod(Description = "提供一個用於一次只上傳由 Position 位置起始的, Bytes 位元組的 FileName 檔案塊存入伺服器端相應檔案的相應位元組位置! 建議用戶端非同步呼叫")]
// 這裡只要多提供一個 Position 參數,餘下的再由用戶端調用非同步該方法,就輕鬆達到目的了!
public string UploadFileChunkBytes(byte[] Bytes,int Position,string FileName)
{
try
{
FileStream fs = new FileStream(Server.MapPath(".") + "\\" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
//該 Bytes 的位元組要寫到 伺服器端 相應檔案的從 Position 開始的位元組
fs.Position = Position;
fs.Write(Bytes, 0, Bytes.Length);
fs.Close();
fs = null;
return FileName + " 檔案塊: 位置[" + Position + "," + (Position + Bytes.Length) + "] 大小(" + Bytes.Length + ") 上傳成功!";
}
catch (Exception e)
{
return e.Message;
}
}

[WebMethod]
public byte[] DownloadFileBytes(string FileName)
{
if (File.Exists(FileName))
{
try
{
FileStream fs = File.OpenRead(FileName);
int i = (int) fs.Length;
byte[] ba = new byte[i];
fs.Read(ba,0,i);
fs.Close();
return ba;
}
catch
{
return new byte[0];
}
}
else
{
return new byte[0];
}
}
}

//=======================================================================

Client Side:
3. UpDownloadProxy.cs :
本檔案由如下命令產生
% Visual Studio .Net 2003 安裝目錄下的 %\SDK\v1.1\Bin\wsdl.exe
具體命令列如下:
wsdl.exe /l:CS /out:UpDownloadProxy.cs http://localhost/MyWebServices/updownload.asmx?wsdl
產生的本地的用戶端代理類代碼裡已經為每個 Web Method 產生了可非同步和同步執行的方法,例如:
public string HelloWorld() {}
public System.IAsyncResult BeginHelloWorld(...) {}
public string EndHelloWorld(...) {}

下面是該命令列產生的完整的 UpDownloadProxy.cs 代碼,就不修改了:
/*

通過執行如下命令列編譯,產生 UpDownloadProxy.dll :
csc /t:library UpDownloadProxy.cs

*/

//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version: 1.1.4322.573
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------

//
// 此原始碼由 wsdl, Version=1.1.4322.573 自動產生。
//
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;

/// <remarks/>
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="Service1Soap", Namespace="http://tempuri.org/")]
public class Service1 : System.Web.Services.Protocols.SoapHttpClientProtocol {

/// <remarks/>
public Service1() {
this.Url = "http://localhost/MyWebServices/updownload.asmx";
}

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string HelloWorld() {
object[] results = this.Invoke("HelloWorld", new object[0]);
return ((string)(results[0]));
}

/// <remarks/>
public System.IAsyncResult BeginHelloWorld(System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("HelloWorld", new object[0], callback, asyncState);
}

/// <remarks/>
public string EndHelloWorld(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/CreateBlankFile", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string CreateBlankFile(string FileName, int Length) {
object[] results = this.Invoke("CreateBlankFile", new object[] {
FileName,
Length});
return ((string)(results[0]));
}

/// <remarks/>
public System.IAsyncResult BeginCreateBlankFile(string FileName, int Length, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("CreateBlankFile", new object[] {
FileName,
Length}, callback, asyncState);
}

/// <remarks/>
public string EndCreateBlankFile(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/UploadFileBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string UploadFileBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] System.Byte[] Bytes, string FileName) {
object[] results = this.Invoke("UploadFileBytes", new object[] {
Bytes,
FileName});
return ((string)(results[0]));
}

/// <remarks/>
public System.IAsyncResult BeginUploadFileBytes(System.Byte[] Bytes, string FileName, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("UploadFileBytes", new object[] {
Bytes,
FileName}, callback, asyncState);
}

/// <remarks/>
public string EndUploadFileBytes(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/UploadFileChunkBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string UploadFileChunkBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] System.Byte[] Bytes, int Position, string FileName) {
object[] results = this.Invoke("UploadFileChunkBytes", new object[] {
Bytes,
Position,
FileName});
return ((string)(results[0]));
}

/// <remarks/>
public System.IAsyncResult BeginUploadFileChunkBytes(System.Byte[] Bytes, int Position, string FileName, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("UploadFileChunkBytes", new object[] {
Bytes,
Position,
FileName}, callback, asyncState);
}

/// <remarks/>
public string EndUploadFileChunkBytes(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}

/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/DownloadFileBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")]
public System.Byte[] DownloadFileBytes(string FileName) {
object[] results = this.Invoke("DownloadFileBytes", new object[] {
FileName});
return ((System.Byte[])(results[0]));
}

/// <remarks/>
public System.IAsyncResult BeginDownloadFileBytes(string FileName, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("DownloadFileBytes", new object[] {
FileName}, callback, asyncState);
}

/// <remarks/>
public System.Byte[] EndDownloadFileBytes(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((System.Byte[])(results[0]));
}
}

//=======================================================================
4. UpDownloadClient.cs :
該程式才是真正實現檔案分塊多點非同步上傳的核心代碼:

/*

通過執行如下命令列編譯:
csc updownloadClient.cs /r:updownloadproxy.dll

*/
using System;
using System.IO;

public class Class1
{
static void Main(string[] args)
{
//Download(ServerSidepath, ClientSidePath)
Download(@"e:\test.jpg", @"f:\test_local.jpg");
System.Console.WriteLine("down End");

System.Console.WriteLine("同步 up file exec ...");
UploadFile(@"e:\Northwind.mdb");
System.Console.WriteLine("同步 up file End\n");

System.Console.WriteLine("非同步 up chunks exec ...");
UploadFileChunks(@"e:\test.rar", 64);
System.Console.ReadLine();
}

public static void UploadFile(string LocalFileName)
{
Service1 xx = new Service1();
FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
//調用 "同步執行" 的本地 Web Sevices 代理類的 方法,相當於同步調用了 Web Method !
xx.UploadFileBytes(buffer, System.IO.Path.GetFileName(LocalFileName));
}

//指定要上傳的本地檔案的路徑,及每次上傳檔案塊的大小
public static void UploadFileChunks(string LocalFileName,int ChunkSize)
{
Service1 xx = new Service1();
string filename = System.IO.Path.GetFileName(LocalFileName);

FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path
//fs = File.OpenRead(LocalFileName);

int r = (int) fs.Length; //用於記錄剩餘還未上傳的位元組數,初值是檔案的大小

//調用 "同步執行" 的本地 Web Sevices 代理類的 方法,相當於同步調用了 Web Method !
//預定伺服器端空間
xx.CreateBlankFile(filename,r);
int size = ChunkSize * 1024;
int k = 0; //用於記錄已經上傳的位元組數
i++; //用於記錄上傳的檔案塊數
while (r >= size)
{
byte[] buffer = new byte[size];
fs.Read(buffer,0,buffer.Length);
//調用 "非同步執行" 的本地 Web Sevices 代理類的 方法,相當於非同步呼叫了 Web Method !
//該 buffer 的位元組要寫到 伺服器端 相應檔案的從 Position = k 開始的位元組
xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx);
k += size;
r -= size;
i++;
}
if (r > 0) //剩餘的零頭
{
byte[] buffer = new byte[r];
fs.Read(buffer,0,buffer.Length);
//調用 "非同步執行" 的本地 Web Sevices 代理類的 方法,相當於非同步呼叫了 Web Method !
//該 buffer 的位元組要寫到 伺服器端 相應檔案的從 Position = k 開始的位元組
xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx);
i++;
}
fs.Close();

}

private static int i = -1; //用於記錄上傳的檔案塊數

private static void UploadFileChunkCallback(IAsyncResult ar)
{
Service1 x = (Service1) ar.AsyncState;
Console.WriteLine(x.EndUploadFileChunkBytes(ar));
if ( --i == 0)
{
Console.WriteLine("非同步 up all chunks end");
}
}

public static void Download(string ServerSideFileName,string LocalFileName)
{
Service1 xx = new Service1();
byte[] ba = xx.DownloadFileBytes(ServerSideFileName); //Server Side Path

FileStream fs = new FileStream(LocalFileName, FileMode.Create); //Client Side Path
fs.Write(ba,0,ba.Length);
fs.Close();
}
}

//===========================================================================
至此我們通過純手工的方式完成了任務,之所以不用 VS 就是為了讓碼子簡潔明了!
Microshaoft .Night 就是這麼平易近人! (PMPMP to MS)
通過 Web Sevices 上傳檔案非常簡單,甚至比傳統的 http Web 上傳還簡單!
同時較輕鬆地就實現了檔案分塊多點非同步上傳:
Server 端代碼沒啥特殊的!
Client 端代碼稍微複雜些!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.