分享
 
 
 

实现支持文件分块多点异步上传的 Web Services 及其客户端(非Web)应用程序调用相关异步执行的 Web Method

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

实现支持文件分块多点异步上传的 Web Services 及其客户端(非Web)应用程序调用相关异步执行的 Web Method

本文的客户端应用程序不包括 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 端代码稍微复杂些!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有