本文的客户端应用程序不包括ASP.NetWeb应用程序!
本文假设URL:http://localhost/mywebservices/updownload.asmx
共有4个程序文件(Web.Config就不赘述了)
ServerSide:
标题中所提到的"异步"其实在服务器端的程序并没有什么特殊的,而主要是通过客户端应用程序
异步调用相关WebMethod实现的!
1.updownload.asmx,位于IIS的某个Web共享目录,代码如下,只有一句话:
<%@WebServiceLanguage="c#"Codebehind="UpDownLoad.asmx.cs"Class="Service1"%>
2.updownload.asmx.cs,即:updownload.asmx的Codebehind,位于IIS的某个Web共享目录的bin子目录下,代码如下:
/*
本文件位于Web共享目录的bin子目录下,通过执行如下命令行编译:
csc/t:libraryupdownload.asmx.cs
*/
usingSystem.Diagnostics;
usingSystem.Web;
usingSystem.Web.Services;
usingSystem.IO;
usingSystem;
publicclassService1:System.Web.Services.WebService
{
[WebMethod]
publicstringHelloWorld()
{
return"HelloWorld";
}
//从WebMethod本身,其实看不出"同步"还是"异步"
[WebMethod(Description="为了支持多点分块异步上传文件,此方法必须由客户端预先调用,以便在服务器端生成指定FileName和Length大小的空白文件预定空间!建议客户端同步调用")]
publicstringCreateBlankFile(stringFileName,intLength)//建议由客户端同步调用
{
FileStreamfs=newFileStream(Server.MapPath(".")+""+FileName,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
fs.Write(newbyte[Length],0,Length);
fs.Close();
fs=null;
returnFileName+"("+Length+")空白文件已经创建!";
}
[WebMethod(Description="提供一个用于一次完整上传整个文件的方法!建议客户端同步调用")]
publicstringUploadFileBytes(byte[]Bytes,stringFileName)
{
returnUploadFileChunkBytes(Bytes,0,FileName);
}
[WebMethod(Description="提供一个用于一次只上传由Position位置起始的,Bytes字节的FileName文件块存入服务器端相应文件的相应字节位置!建议客户端异步调用")]
//这里只要多提供一个Position参数,余下的再由客户端调用异步的该方法,就轻松达到目的了!
publicstringUploadFileChunkBytes(byte[]Bytes,intPosition,stringFileName)
{
try
{
FileStreamfs=newFileStream(Server.MapPath(".")+""+FileName,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.ReadWrite);
//该Bytes的字节要写到服务器端相应文件的从Position开始的字节
fs.Position=Position;
fs.Write(Bytes,0,Bytes.Length);
fs.Close();
fs=null;
returnFileName+"文件块:位置["+Position+","+(Position+Bytes.Length)+"]大小("+Bytes.Length+")上传成功!";
}
catch(Exceptione)
{
returne.Message;
}
}
[WebMethod]
publicbyte[]DownloadFileBytes(stringFileName)
{
if(File.Exists(FileName))
{
try
{
FileStreamfs=File.OpenRead(FileName);
inti=(int)fs.Length;
byte[]ba=newbyte[i];
fs.Read(ba,0,i);
fs.Close();
returnba;
}
catch
{
returnnewbyte[0];
}
}
else
{
returnnewbyte[0];
}
}
}
//=======================================================================
ClientSide:
3.UpDownloadProxy.cs:
本文件由如下命令生成
%VisualStudio.Net2003安装目录下的%SDKv1.1Binwsdl.exe
具体命令行如下:
wsdl.exe/l:CS/out:UpDownloadProxy.cshttp://localhost/MyWebServices/updownload.asmx?wsdl
生成的本地的客户端代理类代码里已经为每个WebMethod生成了可异步和同步执行的方法,例如:
publicstringHelloWorld(){}
publicSystem.IAsyncResultBeginHelloWorld(...){}
publicstringEndHelloWorld(...){}
下面是该命令行生成的完整的UpDownloadProxy.cs代码,就不修改了:
/*
通过执行如下命令行编译,生成UpDownloadProxy.dll:
csc/t:libraryUpDownloadProxy.cs
*/
//------------------------------------------------------------------------------
//<autogenerated>
//Thiscodewasgeneratedbyatool.
//RuntimeVersion:1.1.4322.573
//
//Changestothisfilemaycauseincorrectbehaviorandwillbelostif
//thecodeisregenerated.
//</autogenerated>
//------------------------------------------------------------------------------
//
//此源代码由wsdl,Version=1.1.4322.573自动生成。
//
usingSystem.Diagnostics;
usingSystem.Xml.Serialization;
usingSystem;
usingSystem.Web.Services.Protocols;
usingSystem.ComponentModel;
usingSystem.Web.Services;
///<remarks/>
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="Service1Soap",Namespace="http://tempuri.org/")]
publicclassService1:System.Web.Services.Protocols.SoapHttpClientProtocol{
///<remarks/>
publicService1(){
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)]
publicstringHelloWorld(){
object[]results=this.Invoke("HelloWorld",newobject[0]);
return((string)(results[0]));
}
///<remarks/>
publicSystem.IAsyncResultBeginHelloWorld(System.AsyncCallbackcallback,objectasyncState){
returnthis.BeginInvoke("HelloWorld",newobject[0],callback,asyncState);
}
///<remarks/>
publicstringEndHelloWorld(System.IAsyncResultasyncResult){
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)]
publicstringCreateBlankFile(stringFileName,intLength){
object[]results=this.Invoke("CreateBlankFile",newobject[]{
FileName,
Length});
return((string)(results[0]));
}
///<remarks/>
publicSystem.IAsyncResultBeginCreateBlankFile(stringFileName,intLength,System.AsyncCallbackcallback,objectasyncState){
returnthis.BeginInvoke("CreateBlankFile",newobject[]{
FileName,
Length},callback,asyncState);
}
///<remarks/>
publicstringEndCreateBlankFile(System.IAsyncResultasyncResult){
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)]
publicstringUploadFileBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")]System.Byte[]Bytes,stringFileName){
object[]results=this.Invoke("UploadFileBytes",newobject[]{
Bytes,
FileName});
return((string)(results[0]));
}
///<remarks/>
publicSystem.IAsyncResultBeginUploadFileBytes(System.Byte[]Bytes,stringFileName,System.AsyncCallbackcallback,objectasyncState){
returnthis.BeginInvoke("UploadFileBytes",newobject[]{
Bytes,
FileName},callback,asyncState);
}
///<remarks/>
publicstringEndUploadFileBytes(System.IAsyncResultasyncResult){
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)]
publicstringUploadFileChunkBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")]System.Byte[]Bytes,intPosition,stringFileName){
object[]results=this.Invoke("UploadFileChunkBytes",newobject[]{
Bytes,
Position,
FileName});
return((string)(results[0]));
}
///<remarks/>
publicSystem.IAsyncResultBeginUploadFileChunkBytes(System.Byte[]Bytes,intPosition,stringFileName,System.AsyncCallbackcallback,objectasyncState){
returnthis.BeginInvoke("UploadFileChunkBytes",newobject[]{
Bytes,
Position,
FileName},callback,asyncState);
}
///<remarks/>
publicstringEndUploadFileChunkBytes(System.IAsyncResultasyncResult){
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")]
publicSystem.Byte[]DownloadFileBytes(stringFileName){
object[]results=this.Invoke("DownloadFileBytes",newobject[]{
FileName});
return((System.Byte[])(results[0]));
}
///<remarks/>
publicSystem.IAsyncResultBeginDownloadFileBytes(stringFileName,System.AsyncCallbackcallback,objectasyncState){
returnthis.BeginInvoke("DownloadFileBytes",newobject[]{
FileName},callback,asyncState);
}
///<remarks/>
publicSystem.Byte[]EndDownloadFileBytes(System.IAsyncResultasyncResult){
object[]results=this.EndInvoke(asyncResult);
return((System.Byte[])(results[0]));
}
}
//=======================================================================
4.UpDownloadClient.cs:
该程序才是真正实现文件分块多点异步上传的核心代码:
/*
通过执行如下命令行编译:
cscupdownloadClient.cs/r:updownloadproxy.dll
*/
usingSystem;
usingSystem.IO;
publicclassClass1
{
staticvoidMain(string[]args)
{
//Download(ServerSidepath,ClientSidePath)
Download(@"e:test.jpg",@"f:test_local.jpg");
System.Console.WriteLine("downEnd");
System.Console.WriteLine("同步upfileexec...");
UploadFile(@"e:Northwind.mdb");
System.Console.WriteLine("同步upfileEndn");
System.Console.WriteLine("异步upchunksexec...");
UploadFileChunks(@"e:test.rar",64);
System.Console.ReadLine();
}
publicstaticvoidUploadFile(stringLocalFileName)
{
Service1xx=newService1();
FileStreamfs=newFileStream(LocalFileName,FileMode.Open);//ClientSidePath
byte[]buffer=newbyte[fs.Length];
fs.Read(buffer,0,buffer.Length);
//调用"同步执行"的本地WebSevices代理类的方法,相当于同步调用了WebMethod!
xx.UploadFileBytes(buffer,System.IO.Path.GetFileName(LocalFileName));
}
//指定要上传的本地文件的路径,及每次上传文件块的大小
publicstaticvoidUploadFileChunks(stringLocalFileName,intChunkSize)
{
Service1xx=newService1();
stringfilename=System.IO.Path.GetFileName(LocalFileName);
FileStreamfs=newFileStream(LocalFileName,FileMode.Open);//ClientSidePath
//fs=File.OpenRead(LocalFileName);
intr=(int)fs.Length;//用于记录剩余还未上传的字节数,初值是文件的大小
//调用"同步执行"的本地WebSevices代理类的方法,相当于同步调用了WebMethod!
//预定服务器端空间
xx.CreateBlankFile(filename,r);
intsize=ChunkSize*1024;
intk=0;//用于记录已经上传的字节数
i++;//用于记录上传的文件块数
while(r>=size)
{
byte[]buffer=newbyte[size];
fs.Read(buffer,0,buffer.Length);
//调用"异步执行"的本地WebSevices代理类的方法,相当于异步调用了WebMethod!
//该buffer的字节要写到服务器端相应文件的从Position=k开始的字节
xx.BeginUploadFileChunkBytes(buffer,k,filename,newAsyncCallback(UploadFileChunkCallback),xx);
k+=size;
r-=size;
i++;
}
if(r>0)//剩余的零头
{
byte[]buffer=newbyte[r];
fs.Read(buffer,0,buffer.Length);
//调用"异步执行"的本地WebSevices代理类的方法,相当于异步调用了WebMethod!
//该buffer的字节要写到服务器端相应文件的从Position=k开始的字节
xx.BeginUploadFileChunkBytes(buffer,k,filename,newAsyncCallback(UploadFileChunkCallback),xx);
i++;
}
fs.Close();
}
privatestaticinti=-1;//用于记录上传的文件块数
privatestaticvoidUploadFileChunkCallback(IAsyncResultar)
{
Service1x=(Service1)ar.AsyncState;
Console.WriteLine(x.EndUploadFileChunkBytes(ar));
if(--i==0)
{
Console.WriteLine("异步upallchunksend");
}
}
publicstaticvoidDownload(stringServerSideFileName,stringLocalFileName)
{
Service1xx=newService1();
byte[]ba=xx.DownloadFileBytes(ServerSideFileName);//ServerSidePath
FileStreamfs=newFileStream(LocalFileName,FileMode.Create);//ClientSidePath
fs.Write(ba,0,ba.Length);
fs.Close();
}
}
//===========================================================================
至此我们通过纯手工的方式完成了任务,之所以不用VS就是为了让码子简洁明了!
Microshaoft.Night就是这么平易近人!(PMPMPtoMS)
通过WebSevices上传文件非常简单,甚至比传统的httpWeb上传还简单!
同时较轻松地就实现了文件分块多点异步上传:
Server端代码没啥特殊的!
Client端代码稍微复杂些!
【asp.net下实现支持文件分块多点异步上传的 Web Services】相关文章:
★ 在asp.net下实现Option条目中填充前导空格的方法