asp.net自定义服务器控件-基于jquery的AjaxUpload封装的服务器控件
示例项目结构如下:
一、mycontrols为控件项目
1、控件资源
jquery-1.4.1.min.js-使用的jquery类库
ajaxupload.3.9.js -基于ajaxupload3.9版本
uploadcontrol.js -上传控件中的主功能的核心js
uploadcontrol.css -上传控的样式
loading.gif -上传中的过渡动画
以上资源需在项目中的properties下的assemblyinfo.cs文件中定义,代码如下:
[csharp]
using system.reflection;
using system.runtime.compilerservices;
using system.runtime.interopservices;
using system.web.ui;
// 有关程序集的常规信息通过下列特性集
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: assemblytitle("mycontrols")]
[assembly: assemblydescription("")]
[assembly: assemblyconfiguration("")]
[assembly: assemblycompany("sky123.org")]
[assembly: assemblyproduct("mycontrols")]
[assembly: assemblycopyright("copyright © sky123.org 2013")]
[assembly: assemblytrademark("")]
[assembly: assemblyculture("")]
// 将 comvisible 设置为 false 会使此程序集中的类型
// 对 com 不可见。如果需要从 com 访问此程序集中的某个类型,
// 请针对该类型将 comvisible 特性设置为 true。
[assembly: comvisible(false)]
// 如果此项目向 com 公开,则下列 guid 用于类型库的 id
[assembly: guid("110396a2-e863-49fc-b55c-82cee89a1c31")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 内部版本号
// 修订号
//
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: assemblyversion("1.0.*")]
[assembly: assemblyversion("1.0.0.0")]
[assembly: assemblyfileversion("1.0.0.0")]
[assembly: webresource("mycontrols.uploadcontrol.uploadcontrol.css", "text/css", performsubstitution = true)]
[assembly: webresource("mycontrols.uploadcontrol.loading.gif", "image/gif")]
[assembly: webresource("mycontrols.uploadcontrol.jquery-1.4.1.min.js", "text/javascript")]
[assembly: webresource("mycontrols.uploadcontrol.ajaxupload.3.9.js", "text/javascript")]
[assembly: webresource("mycontrols.uploadcontrol.uploadcontrol.js", "text/javascript")]
2、核心代码
1、uploadcontrol.cs文件为控件核心代码,代码如下:
[csharp]
using system;
using system.collections.generic;
using system.componentmodel;
using system.configuration;
using system.io;
using system.linq;
using system.text;
using system.threading.tasks;
using system.web;
using system.web.sessionstate;
using system.web.ui;
using system.web.ui.htmlcontrols;
using system.web.ui.webcontrols;
namespace mycontrols
{
[defaultproperty("uploadcontrol")]
[toolboxdata("<{0}:uploadcontrol runat=server></{0}:uploadcontrol>")]
public class uploadcontrol : compositecontrol, irequiressessionstate, ihttphandler, ipostbackdatahandler, iscriptcontrol
{
#region 属性
private string uploadfiledirectory = "uploadfiles";
private string loadingimageurl;
private htmlgenericcontrol container;
private linkbutton btnupload;
private htmlgenericcontrol ploading;
private htmlgenericcontrol pfiles;
private button btnpost;
private hiddenfield hf_files;
private hiddenfield hf_filetypes;
private hiddenfield hf_filesize;
private scriptmanager _scriptmanager;
[browsable(false)]
public scriptmanager scriptmanager
{
get
{
if (_scriptmanager != null)
{
return _scriptmanager;
}
else if (page != null)
{
scriptmanager scriptmanager = scriptmanager.getcurrent(page);
if (scriptmanager != null)
{
this._scriptmanager = scriptmanager;
return scriptmanager;
}
}
throw new httpexception("使用uploadcontrol控件要求页面上必须存在scriptmanager");
}
set
{
this._scriptmanager = value;
}
}
[bindable(true)]
[category("appearance")]
[defaultvalue("上传")]
[localizable(true)]
[description("上传按钮显示的文字,默认为‘上传’")]
public string text
{
get { return this.btnupload.text; }
set { this.btnupload.text = value; }
}
[bindable(true)]
[category("appearance")]
[defaultvalue("button white")]
[localizable(true)]
[description("上传按钮的css样式")]
public string css
{
get { return btnupload.cssclass; }
set { btnupload.cssclass = value; }
}
/// <summary>
/// 文件列表
/// </summary>
[bindable(true)]
[defaultvalue("")]
[localizable(true)]
[description("文件列表")]
[browsable(false)]
public list<attachment> files
{
get
{
list<attachment> res = new list<attachment>();
if (!string.isnullorempty(this.hf_files.value))
{
string[] strs = this.hf_files.value.split('|');
foreach (var item in strs)
{
if (!string.isnullorempty(item))
{
attachment attach = new attachment()
{
displayname = item.split('*')[0],
name = item.split('*')[1],
};
res.add(attach);
}
}
}
return res;
}
set
{
if (value.count > 0)
{
foreach (var item in value)
{
this.hf_files.value += item.displayname + "*" + item.name + "|";
}
}
}
}
/// <summary>
/// 是否为多文件上传
/// </summary>
[bindable(true)]
[defaultvalue(false)]
[localizable(true)]
[description("是否为多文件上传,默认为false")]
public bool ismutifileupload
{
get;
set;
}
/// <summary>
/// 是否显示上传按钮
/// </summary>
[bindable(true)]
[defaultvalue(true)]
[localizable(true)]
[description("是否显示上传按钮,默认为true")]
public bool isshowuploadbutton
{
get;
set;
}
/// <summary>
/// 是否显示删除按钮
/// </summary>
[bindable(true)]
[defaultvalue(true)]
[localizable(true)]
[description("是否显示删除按钮,默认为true")]
public bool isshowdeletebutton
{
get;
set;
}
/// <summary>
/// 是否显示下载按钮
/// </summary>
[bindable(true)]
[defaultvalue(true)]
[localizable(true)]
[description("是否显示下载按钮,默认为true")]
public bool isshowdownloadbutton
{
get;
set;
}
/// <summary>
/// 允许上传的文件格式
/// </summary>
[bindable(true)]
[defaultvalue("*")]
[localizable(true)]
[description("允许上传的文件格式,如果为'*'代表所有文件,否则多个之间用'|'分隔 如: gif|jpg|doc,默认为'*'")]
public string allowfiletype
{
get { return this.hf_filetypes.value; }
set { this.hf_filetypes.value = value; }
}
/// <summary>
/// 允许上传的文件大小
/// </summary>
[bindable(true)]
[defaultvalue("10mb")]
[localizable(true)]
[description("允许上传的文件大小,如:10kb,10mb,默认为10mb")]
public string allowfilesize
{
get { return this.hf_filesize.value; }
set { this.hf_filesize.value = value; }
}
/// <summary>
/// 允许上传的文件个数
/// </summary>
[bindable(true)]
[defaultvalue(1)]
[localizable(true)]
[description("允许上传的文件个数 默认为1")]
public string allowfilecount
{
get { return btnupload.attributes["maxfilecount"]; }
set { btnupload.attributes["maxfilecount"] = value; }
}
/// <summary>
/// 是否自动初始化控件相关的web.config配置
/// </summary>
[bindable(true)]
[defaultvalue(false)]
[localizable(true)]
[description("是否自动初始化控件相关的web.config配置")]
public bool isautoinitconfig
{
get;
set;
}
#endregion
#region 事件
public uploadcontrol()
{
ensurechildcontrols();
}
/// <summary>
/// 创建内容控件(最先执行)
/// </summary>
protected override void createchildcontrols()
{
base.createchildcontrols();
container = new htmlgenericcontrol("p");
container.id = "container";
this.controls.add(container);
btnupload = new linkbutton();
btnupload.id = "btnupload";
btnupload.cssclass = css;
btnupload.style.add("float", "left");
ploading = new htmlgenericcontrol("p");
ploading.id = "ploading";
ploading.style.add("float", "left");
ploading.style.add("padding-left", "2px");
pfiles = new htmlgenericcontrol("p");
pfiles.id = "pfiles";
pfiles.style.add("float", "left");
pfiles.style.add("padding-left", "5px");
btnpost = new button();
btnpost.id = "btnpost";
btnpost.style.add("display", "none");
hf_files = new hiddenfield();
hf_files.id = "hf_files";
container.controls.add(btnupload);
container.controls.add(ploading);
container.controls.add(pfiles);
container.controls.add(btnpost);
container.controls.add(hf_files);
hf_filetypes = new hiddenfield();
hf_filetypes.id = "hf_filetypes";
hf_filesize = new hiddenfield();
hf_filesize.id = "hf_filesize";
this.controls.add(hf_filetypes);
this.controls.add(hf_filesize);
//设置默认值写在这里最合适
setattributedefaultvalue();
btnupload.attributes.add("maxfilecount", this.allowfilecount);
}
/// <summary>
/// 加载事件(在createchildcontrols之后执行)
/// </summary>
/// <param name="e"></param>
protected override void onload(eventargs e)
{
base.onload(e);
loadingimageurl = this.page.clientscript.getwebresourceurl(this.gettype(), "mycontrols.uploadcontrol.loading.gif");
page.clientscript.registerstartupscript(this.gettype(), this.clientid + "_reinit", @"<script type='text/javascript'>var prm = sys.webforms.pagerequestmanager.getinstance();prm.add_endrequest(function () {$(document).ready(function () {init('" + this.clientid + "','" + loadingimageurl + "');});});</script>");
if (isshowuploadbutton)
this.btnupload.visible = true;
else
this.btnupload.visible = false;
if (ismutifileupload)
multifile();
else
singlefile();
}
/// <summary>
/// prerender事件(在onload之后执行)
/// </summary>
/// <param name="e"></param>
protected override void onprerender(eventargs e)
{
page.registerrequirespostback(this);
base.onprerender(e);
if (isautoinitconfig)
{
configmanager.adduploaddirectoryconfig("uploadfilepath", "uploadfiles");
//configmanager.registercontrolconfig();
configmanager.addrequestconfig(2097150, 3600);
configmanager.addrequestsecurityconfig();
configmanager.addasyncajaxconfig();
}
if (!designmode)
{
this.scriptmanager.registerscriptcontrol<uploadcontrol>(this);
htmllink link = page.header.findcontrol("uploadcontrolcss") as htmllink;
if (link == null) //防止重复
{
link = new htmllink();
link.id = "uploadcontrolcss";
link.attributes["type"] = "text/css";
link.href = page.clientscript.getwebresourceurl(this.gettype(), "mycontrols.uploadcontrol.uploadcontrol.css");
link.attributes["rel"] = "stylesheet";
page.header.controls.add(link);
}
page.clientscript.registerclientscriptresource(this.gettype(), "mycontrols.uploadcontrol.jquery-1.4.1.min.js");
page.clientscript.registerclientscriptresource(this.gettype(), "mycontrols.uploadcontrol.ajaxupload.3.9.js");
//这句可以不要 在getscriptreferences()方法也可以做
//page.clientscript.registerclientscriptresource(this.gettype(), "mycontrols.uploadcontrol.uploadcontrol.js");
page.clientscript.registerstartupscript(this.gettype(), this.clientid + "_init", "<script>$(document).ready(function () {init('" + this.clientid + "','" + loadingimageurl + "');});</script>");
}
}
#endregion
#region 方法
/// <summary>
/// 设置属性的默认值
/// </summary>
void setattributedefaultvalue()
{
this.text = "上传";
//this.css = "button white";
this.allowfiletype = "*";
this.allowfilesize = "10mb";
this.allowfilecount = "1";
this.ismutifileupload = false;
this.isshowuploadbutton = true;
this.isshowdeletebutton = true;
this.isshowdownloadbutton = true;
this.isautoinitconfig = false;
if(configurationmanager.appsettings["uploadfilepath"]!=null)
uploadfiledirectory = configurationmanager.appsettings["uploadfilepath"].tostring();
}
/// <summary>
/// 单文件上传时输出
/// </summary>
void singlefile()
{
string uploadpath =uploadfiledirectory;
string innerhtml = string.empty;
if (files.count > 0)
{
int fileindex = files.count - 1;
var item = files[fileindex];
for (int i = 0; i < files.count; i++)
{
//总是删除之前的,用最新的一个替换
if (i != fileindex)
file.delete(page.server.mappath(string.format("~/{0}/", uploadpath)) + files[i].name);
}
this.hf_files.value = item.displayname + "*" + item.name + "|";
innerhtml = string.format("<span title='{0}'>{1}</span> {2} {3}", item.displayname, formatitem(item.displayname), getdeletehtml(item.name), getdownloadhtml(item.displayname, item.name));
}
pfiles.innerhtml = innerhtml;
}
/// <summary>
/// 多文件上传时输出
/// </summary>
void multifile()
{
string innerhtml = string.empty;
foreach (var item in files)
{
innerhtml += string.format("<li><span title='{0}'>{1}</span> {2} {3}</li>", item.displayname, formatitem(item.displayname), getdeletehtml(item.name), getdownloadhtml(item.displayname, item.name));
}
if (files.count > 0)
{
innerhtml = "<ul>" + innerhtml + "</ul>";
pfiles.style["padding-left"] = "5px";
pfiles.style["padding-top"] = "20px";
pfiles.style.remove("float");
}
pfiles.innerhtml = innerhtml;
}
/// <summary>
/// 获取删除html串
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
string getdeletehtml(string filename)
{
if (isshowdeletebutton)
return string.format("<a href='#' onclick='removefile(\"{0}\",\"{1}\",\"{2}\")'>删除</a>",this.clientid, filename,loadingimageurl);
else
return string.empty;
}
/// <summary>
/// 获取下载html串
/// </summary>
/// <returns></returns>
string getdownloadhtml(string displayname, string filename)
{
if (isshowdownloadbutton)
{
var showname = page.server.urlencode(displayname);
var realname = page.server.urlencode(filename);
string path = page.server.urldecode(uploadfiledirectory);//文件路径
string path = page.server.mappath(path) + "\\" + filename;
if (file.exists(path))
return string.format("<a href='mycontrols?action=download&displayname={0}&filename={1}'>下载</a>", showname, realname);
else
return string.format("<a target='_blank' href='mycontrols?action=download&displayname={0}&filename={1}'>下载</a>", showname, realname);
}
else
return string.empty;
}
/// <summary>
/// 格式化长度
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
string formatitem(string item)
{
int maxlength = 15;
return getstr(item, maxlength, "...");
}
/// <summary>
/// 根据字符串s超过指定长度l时,对结尾endstr的处理
/// </summary>
/// <param name="s"></param>
/// <param name="l"></param>
/// <param name="endstr"></param>
/// <returns></returns>
string getstr(string s, int l, string endstr)
{
string temp = s.substring(0, (s.length < l + 1) ? s.length : l + 1);
byte[] encodedbytes = system.text.asciiencoding.ascii.getbytes(temp);
string outputstr = "";
int count = 0;
for (int i = 0; i < temp.length; i++)
{
if ((int)encodedbytes[i] == 63)
count += 2;
else
count += 1;
if (count <= l - endstr.length)
outputstr += temp.substring(i, 1);
else if (count > l)
break;
}
if (count <= l)
{
outputstr = temp;
endstr = "";
}
outputstr += endstr;
return outputstr;
}
#endregion
#region ipostbackdatahandler相关
public bool loadpostdata(string postdatakey, system.collections.specialized.namevaluecollection postcollection)
{
return true;
}
public void raisepostdatachangedevent()
{
}
#endregion
#region ihttphandler相关
public bool isreusable
{
get
{
return false;
}
}
public void processrequest(httpcontext context)
{
try
{
if (context.request["action"] != null)
{
switch (context.request["action"].tostring())
{
case "upload":
upload(context);
break;
case "remove":
remove(context);
break;
case "download":
download(context);
break;
}
}
}
catch (exception ex)
{
context.response.write("error|" + ex.message);
}
}
/// <summary>
/// 上传附件
/// </summary>
/// <param name="context"></param>
void upload(httpcontext context)
{
double maxfilesize = getmaxsize(context.request["filesize"].tostring());
httppostedfile hpffile = context.request.files["uploadfile"];
if (hpffile.contentlength <= maxfilesize)
{
string[] strs = hpffile.filename.split('.');
string extname = strs[strs.length - 1];
string filename = "p" + guid.newguid().tostring().replace("-", "") + "." + extname;
string path = context.server.mappath(string.format("~/{0}/", uploadfiledirectory));
if (!directory.exists(path))
directory.createdirectory(path);
hpffile.saveas(path + filename);
context.response.write("success|" + filename);
}
else
context.response.write("success|big");
}
/// <summary>
/// 移除附件
/// </summary>
/// <param name="context"></param>
void remove(httpcontext context)
{
var filename = context.request["filename"].tostring();
file.delete(context.server.mappath(string.format("~/{0}/", uploadfiledirectory)) + filename);
context.response.write("success");
}
/// <summary>
/// 下载附件
/// </summary>
/// <param name="context"></param>
void download(httpcontext context)
{
string path = context.server.urldecode(uploadfiledirectory);//文件路径
string displayname = context.server.urldecode(context.request["displayname"]);//文件显示的名称
string filename = context.server.urldecode(context.request["filename"]);//实际文件名称
if (!string.isnullorempty(path))
{
string path = context.server.mappath(path) + "\\" + filename;
if (file.exists(path))
{
using (filestream fs = new filestream(path, filemode.open, fileaccess.read))
{
byte[] btfile = new byte[fs.length];
fs.read(btfile, 0, convert.toint32(fs.length));
output(context, displayname, btfile);
}
}
else
{
context.response.write("<script>alert('文件不存在');window.opener=null;window.open('','_self');window.close();</script>");
}
}
}
/// <summary>
/// 最大文件的大小(单位为字节)
/// </summary>
/// <param name="filesize"></param>
/// <returns></returns>
double getmaxsize(string filesize)
{
double res = -1;
if (filesize.contains("mb"))
res = double.parse(filesize.replace("mb", "").trim()) * 1024 * 1024;
if (filesize.contains("kb"))
res = double.parse(filesize.replace("kb", "").trim()) * 1024;
return res;
}
/// <summary>
/// 输出附件
/// </summary>
void output(httpcontext context, string filename, byte[] obj)
{
context.response.clear();
context.response.bufferoutput = false;
context.response.contentencoding = system.text.encoding.utf8;
context.response.addheader("content-disposition", "attachment;filename=" + context.server.urlencode(filename));
context.response.contenttype = "application/octet-stream";
context.response.outputstream.write(obj, 0, obj.length);
context.response.close();
context.response.end();
}
#endregion
#region iscriptcontrol相关
public ienumerable<scriptdescriptor> getscriptdescriptors()
{
scriptcontroldescriptor descriptor = new scriptcontroldescriptor("mycontrols.uploadcontrol", this.clientid);
yield return descriptor;
}
public ienumerable<scriptreference> getscriptreferences()
{
yield return new scriptreference("mycontrols.uploadcontrol.uploadcontrol.js", this.gettype().assembly.fullname);
}
#endregion
}
}
2、attachment.cs文件为附件类,代码如下:
[csharp]
using system;
using system.collections.generic;
using system.linq;
using system.web;
namespace mycontrols
{
/// <summary>
/// 附件类
/// </summary>
public class attachment
{
/// <summary>
/// 附件id
/// </summary>
public string id
{
get;
set;
}
/// <summary>
/// 附件名称
/// </summary>
public string name
{
get;
set;
}
/// <summary>
/// 附件显示名称
/// </summary>
public string displayname
{
get;
set;
}
/// <summary>
/// 附件路径
/// </summary>
public string path
{
get;
set;
}
}
}
二.mycontrols.test为测试项目
示例图:
1、uploadfiles-该目录为控件默认上传附件的目录,可以在web.config文件中配置
2、default.x-文件为控件demo页面,代码如下:
[html]
<%@ page language="c#" autoeventwireup="true" codebehind="default.aspx.cs" inherits="mycontrols.test.default" %>
<!doctype html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head id="head1" runat="server">
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title></title>
<style type="text/css">
<!--
.onep{width:300px; height:300px;float:left;margin:0 0 0 5px; border:1px #000 solid;}
.twop{width:300px; height:300px;float:left;margin:0 0 0 5px; border:1px #000 solid;}
-->
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:scriptmanager id="scriptmanager1" runat="server"></asp:scriptmanager>
<asp:updatepanel id="updatepanel1" runat="server">
<contenttemplate>
<p class="onep">
<span>单文件上传</span><p/>
<asp:uploadcontrol runat="server" id="uploadcontrol1" text="浏览" allowfilesize="50mb" css="button white"/>
</p>
<p class="twop">
<span>多文件上传</span><p/>
<asp:uploadcontrol runat="server" id="uploadcontrol2" text="浏览"
ismutifileupload="true" allowfilesize="70mb"
allowfilecount="1000" isautoinitconfig="false" css="button white"/>
</p>
<p class="onep"><ul id="ul1" runat="server"></ul></p>
<p class="onep"><ul id="ul2" runat="server"></ul></p>
<asp:button id="button1" runat="server" text="测试回发" onclick="button1_click"/>
</contenttemplate>
</asp:updatepanel>
</form>
</body>
</html>
default.aspx.cs对应后台代码如下:
[csharp]
using system;
using system.collections.generic;
using system.linq;
using system.web;
using system.web.ui;
using system.web.ui.webcontrols;
namespace mycontrols.test
{
public partial class default : system.web.ui.page
{
protected void page_load(object sender, eventargs e)
{
if (!ispostback)
{
list<attachment> list = new list<attachment>();
list.add(new attachment()
{
displayname = "aa.docx",
name = "aa.docx",
});
uploadcontrol1.files = list;
list.add(new attachment()
{
displayname = "bb.docx",
name = "bb.docx",
});
uploadcontrol2.files = list;
button1_click(null, null);
}
}
protected void button1_click(object sender, eventargs e)
{
var list1 = uploadcontrol1.files;
var list2 = uploadcontrol2.files;
ul1.innerhtml = string.empty;
ul2.innerhtml = string.empty;
foreach (var item in list1)
{
ul1.innerhtml += "<li>" + item.displayname + "</li>";
}
foreach (var item in list2)
{
ul2.innerhtml += "<li>" + item.displayname + "</li>";
}
}
}
}
推荐阅读
-
asp.net自定义服务器控件-基于jquery的AjaxUpload封装的服务器控件
-
asp.net服务器控件button先执行js再执行后台的方法
-
Asp.Net服务器控件开发的Grid实现(四)回发事件
-
Asp.Net服务器控件开发的Grid实现(三)
-
Asp.Net服务器控件开发的Grid实现(二)
-
Asp.Net使用服务器控件Image/ImageButton显示本地图片的方法
-
js jquery获取随机生成id的服务器控件的三种方法
-
Asp.Net使用服务器控件Image/ImageButton显示本地图片的方法
-
jquery dialog open后,服务器端控件失效的快速解决方法
-
基于GridLayout封装的自定义依赖库控件ScheduleView