当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > asp.net下实现支持文件分块多点异步上传的 Web Services

ASP.NET
asp.net GridView控件中模板列CheckBox全选、反选、取消
asp.net GridView 删除时弹出确认对话框(包括内容提示)
asp.net DropDownList 三级联动下拉菜单实现代码
asp DataTable添加列和行的三种方法
Asp.net 页面调用javascript变量的值
asp.net 长文章通过设定的行数分页
asp.net 定时间点执行任务的简易解决办法
asp.net 页面延时五秒,跳转到另外的页面
asp.net 动态输出透明gif图片
asp.net DataList与Repeater用法区别
asp.net Javascript获取CheckBoxList的value
asp.net程序在调式和发布之间图片路径问题的解决方法
asp.net下生成英文字符数字验证码的代码
asp.net 页面版文本框智能提示JSCode (升级版)
ASP.NET URL伪静态重写实现方法
ASP.NET 2.0 中Forms安全认证
asp.net 动态添加多个用户控件
asp.net Repeater显示父子表数据,无闪烁
asp.net 无法获取的内部内容,因为该内容不是文本 的解决方法
asp.net GridView排序简单实现

ASP.NET 中的 asp.net下实现支持文件分块多点异步上传的 Web Services


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-11   浏览: 56 ::
收藏到网摘: n/a

本文的客户端应用程序不包括 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(@"/upload/tech/20091011/20091011143602_13f320e7b5ead1024ac95c3b208610db.jpg", @"/upload/tech/20091011/20091011143603_b1d10e7bafa4421218a51b1e1f1b0ba2.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(@"/upload/tech/20091011/20091011143603_b6d767d2f8ed5d21a44b0e5886680cb9.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 端代码稍微复杂些!