如何用Silverlight在DiscuzNT中实现多文件上传功能?
- 内容介绍
- 文章标签
- 相关推荐
本文共计4723个文字,预计阅读时间需要19分钟。
注意:原文的HTML页面位置依赖于Discuz.Web项目,具体位置请参考官方文档。以下是一篇关于推荐一个Silverlight多文件(大文件)上传开源项目的文章:
《推荐一个Silverlight多文件(大文件)上传开源项目》
近年来,随着互联网技术的飞速发展,大文件上传的需求日益增长。为了满足这一需求,本文将推荐一个基于Silverlight的多文件上传开源项目。
该项目名为Silverlight Multi-File Upload,是一款功能强大的Silverlight客户端应用程序,旨在实现大文件的高效上传。以下是该项目的几个亮点:
1. 支持多文件选择,用户可以一次性上传多个文件。
2.支持大文件上传,单个文件大小可达数GB。
3.采用分片上传技术,提高上传速度和稳定性。
4.支持断点续传,确保上传过程中不会因为网络问题导致上传中断。
5.开源免费,可自由修改和二次开发。
使用该项目的步骤如下:
1. 下载项目源码。
2.将项目导入到Visual Studio中。
3.修改配置文件,设置服务器端上传地址等信息。
4.运行项目,进行测试。
总结:Silverlight Multi-File Upload项目是一款优秀的开源多文件上传工具,适用于各种大文件上传场景。希望本文的推荐对您有所帮助。
注:本文的HTM页面均位于Discuz.Web项目中,大家可以到官方下面最终的程序。
在去年我曾写过一篇文章:“推荐一个Silverlight多文件(大文件)上传的开源项目”。之后
有不少朋友询问这个项目示例在开发和配置上的一些问题。当时因为时间有限没有做过多的说明,
导致有些问题在大家下载完源码之后运行时才出现。今天就以这个项目为原型,简要介绍一下在
DiscuzNT上是如果在该项目基本上,通过完善权限管理,文件大小控制,添加缩略图效果等功能
来大体阐述一下如果开发一个真正的silverlight应用,而不是一个简单的DEMO.
当然本文中所列出的源码是通过reflector获取并添加相应注释的。最终的源码还是要以开放
出来的为准,呵呵:)
好了,开始今天的正文吧!
首先,看一下这个插件在DiscuzNT中的实际运行效果:
当我们在网页中点击“批量上传”按钮时,会运行如下JS脚本(文件位于Discuz.Web\
templates\default_postattachments.htm):
Silverlight.createObject(
"silverlight/UploadFile/ClientBin/MultiFileUpload.xap",
$("silverlightControlHost"),
pluginID,
{
width:'500',
height:'440',
inplaceInstallPrompt:'true',
isWindowless:'true',
background:'transparent',
version:'2.0',
autoUpgrade:'true'
},
{
onLoad:onLoad,
onError:onSilverlightError
},
<%csharp%>
stringauthToken=Discuz.Common.DES.Encode(oluserinfo.Olid.ToString()+","+
oluserinfo.Username.ToString(),oluserinfo.Password.Substring(0,10)).Replace("+","[");
<%/csharp%>
"forumid={forumid},authToken={authToken},max="+max,
"");
}
其会将当前版块id(forumid),认证Token,最大上传数等信息以参数形式传给SL插件,而我专门定
义了一个方法用于获取相应的参数并绑定到sl变量,如下(Page.xaml.cs):
///加载配置参数
///</summary>
///<paramname="initParams"></param>
privatevoidLoadConfiguration(IDictionary<string,string>initParams)
{
stringtryTest=string.Empty;
//加载定制配置信息串
_customParams=initParams["forumid"];
if(initParams.ContainsKey("MaxUploads")&&!string.IsNullOrEmpty(initParams["MaxUploads"]))
int.TryParse(initParams["MaxUploads"],out_maxUpload);
if(initParams.ContainsKey("MaxFileSizeKB")&&!string.IsNullOrEmpty(initParams["MaxFileSizeKB"]))
{
if(int.TryParse(initParams["MaxFileSizeKB"],out_maxFileSize))
_maxFileSize=_maxFileSize*1024;
}
if(initParams.ContainsKey("FileFilter")&&!string.IsNullOrEmpty(initParams["FileFilter"]))
_fileFilter=initParams["FileFilter"];
if(initParams.ContainsKey("forumid")&&!string.IsNullOrEmpty(initParams["forumid"]))
_forumid=Utils.StrToInt(initParams["forumid"],0);
if(initParams.ContainsKey("max")&&!string.IsNullOrEmpty(initParams["max"]))
_maxAttachments=Utils.StrToInt(initParams["max"],0);
CredentialInfo_creInfo=Utils.GetCredentialInfo();
if(_creInfo.UserID<=0)
{
ShowMessageBox("您未登陆系统");
SetUploadButton(false);
return;
}
else
{
MixObjectsSoapClient_client=Utils.CreateServiceClient();
_client.GetAttachmentUploadSetCompleted+=newEventHandler<GetAttachmentUploadSetCompletedEventArgs>
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo,_forumid);
}
}
大家看到在该方法在获取相应初始化参数(initParams)后,会调用Utils.GetCredentialInfo()来获取
用户登陆信息:
///获取认证信息
///</summary>
///<returns></returns>
publicstaticCredentialInfoGetCredentialInfo()
{
CredentialInfo_creinfo=newCredentialInfo();
_creinfo.UserID=Utils.StrToInt(Utils.GetCookie("userid"),0);
_creinfo.Password=Utils.GetCookie("password");
if(App.GetInitParmas.ContainsKey("authToken")&&!string.IsNullOrEmpty(App.GetInitParmas["authToken"]))
_creinfo.AuthToken=App.GetInitParmas["authToken"];
if(App.GetInitParmas.ContainsKey("forumid")&&!string.IsNullOrEmpty(App.GetInitParmas["forumid"]))
_creinfo.ForumID=StrToInt(App.GetInitParmas["forumid"],0);
return_creinfo;
}
其中最主要的就是获取相应的UserID,而这个操作是交给GetCookie来完成的:
{
if(string.IsNullOrEmpty(HtmlPage.Document.Cookies))
returnnull;
//找到想应的cookie键值
stringresult=(fromcin
(fromcookieinHtmlPage.Document.Cookies.Split(';')
wherecookie.Contains(key+"=")
selectcookie.Split('&')).FirstOrDefault()
wherec.Contains(key+"=")
selectc).FirstOrDefault().ToString();
if(string.IsNullOrEmpty(result))
returnnull;
returnresult.Substring(result.IndexOf(key+"=")+key.Length+1);
}
其主要是通过用户本地的Cookie,来获取相应的用户信息。
如果用户的Cookie有效(已登陆过),则直接获取该用户所在用户组及其它相关联的权限信息,
如果无效,则提示用户登陆,同时将SL中的几个上传按钮“置灰”,以免未登陆的用户上传附件。
下面就是其向服务器请求谁信息的代码:
_client.GetAttachmentUploadSetCompleted+=newEventHandler<GetAttachmentUploadSetCompletedEventArgs>
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo,_forumid);
上面客户端请求下面的服务端代码:
///通过指定用户认证信息来获得该用户的上传设置信息
///</summary>
///<paramname="creinfo">用户认证信息</param>
///<returns></returns>
[WebMethod]
publicUploadSetInfoGetAttachmentUploadSet(CredentialInfocreinfo)
{
if(AuthenticateUser(creinfo))
{
UserInfouserinfo=Discuz.Forum.Users.GetUserInfo(creinfo.UserID);
if(userinfo==null)
returnnewUploadSetInfo("","",0,0,false,0,"当前用户信息无效,请尝试刷新");
UserGroupInfousergroupinfo=Discuz.Forum.UserGroups.GetUserGroupInfo(userinfo.Groupid);
if(usergroupinfo==null)
returnnewUploadSetInfo("","",0,0,false,0,"当前用户所属用户组信息无效");
ForumInfoforum=Discuz.Forum.Forums.GetForumInfo(creinfo.ForumID);
if(forum==null)
returnnewUploadSetInfo(null,null,0,0,false,0,"当前版块信息无效,请尝试刷新");
//得到用户可以上传的文件类型
StringBuildersbAttachmentTypeSelect=newStringBuilder();
if(!usergroupinfo.Attachextensions.Trim().Equals(""))
{
sbAttachmentTypeSelect.Append("[id]in(");
sbAttachmentTypeSelect.Append(usergroupinfo.Attachextensions);
sbAttachmentTypeSelect.Append(")");
}
if(!forum.Attachextensions.Equals(""))
{
if(sbAttachmentTypeSelect.Length>0)
sbAttachmentTypeSelect.Append("AND");
sbAttachmentTypeSelect.Append("[id]in(");
sbAttachmentTypeSelect.Append(forum.Attachextensions);
sbAttachmentTypeSelect.Append(")");
}
stringattachextensions=Discuz.Forum.Attachments.GetAttachmentTypeArray(sbAttachmentTypeSelect.ToString());
stringattachextensionsnosize=Discuz.Forum.Attachments.GetAttachmentTypeString(sbAttachmentTypeSelect.ToString());
//得到今天允许用户上传的附件总大小(字节)
intMaxTodaySize=0;
if(creinfo.UserID>0)
MaxTodaySize=Discuz.Forum.Attachments.GetUploadFileSizeByuserid(creinfo.UserID);
intattachsize=usergroupinfo.Maxsizeperday-MaxTodaySize;//今天可上传大小
boolcanpostattach=false;//是否允许上传附件
//是否有上传附件的权限
if(Discuz.Forum.Forums.AllowPostAttachByUserID(forum.Permuserlist,creinfo.UserID))
canpostattach=true;
else
{
if(forum.Postattachperm=="")
{
if(usergroupinfo.Allowpostattach==1)
canpostattach=true;
}
else
{
if(Discuz.Forum.Forums.AllowPostAttach(forum.Postattachperm,usergroupinfo.Groupid))
canpostattach=true;
}
}
returnnewUploadSetInfo(attachextensions,attachextensionsnosize,MaxTodaySize,attachsize,
canpostattach,usergroupinfo.Maxattachsize,"");
}
returnnewUploadSetInfo("","",0,0,false,0,"当前用户信息无效,请尝试刷新");
}
该方法的首先会访问AuthenticateUser方法来进行用户身份验证:
/// <summary>
/// WEB权限认证
///<paramname="creinfo">认证信息</param>
///<returns>是否通过验正</returns>
privateboolAuthenticateUser(CredentialInfocreinfo)
{
if(creinfo.ForumID>0)
{
intolid=Discuz.Forum.OnlineUsers.GetOlidByUid(creinfo.UserID);
if(olid>0)
{
OnlineUserInfooluserinfo=Discuz.Forum.OnlineUsers.GetOnlineUser(olid);
if(oluserinfo.Userid==creinfo.UserID&&
Utils.UrlEncode(Discuz.Forum.ForumUtils.SetCookiePassword(oluserinfo.Password,
GeneralConfigs.GetConfig().Passwordkey))==creinfo.Password&&//检测用户id和口令
creinfo.AuthToken==DES.Encode(string.Format("{0},{1}",oluserinfo.Olid.ToString(),
oluserinfo.Username.ToString()),oluserinfo.Password.Substring(0,10)).Replace("+","["))//检查认证信息
{
returntrue;
}
}
}
returnfalse;
}
其会对用户的UserId与用户在线表中的数据进行比对,以确保其信息有效,同时还会检查AuthToken
来避免用户通过伪造用户信息来进行信息提交。当上面方法返回TRUE时,则将对用户所在版块的权限信息
进行获取,并返回一个名为UploadSetInfo类实例,其包括:
2.用户可以上传的文件类型(不带上传数据大小)
3.得到今天允许用户上传的附件总大小(字节)
4.是否允许上传附件
5.单个附件大小
6.最大允许上传的附件数
7.错误信息 #region上传设置信息类
///<summary>
///上传设置信息类
///</summary>
publicclassUploadSetInfo
{
publicUploadSetInfo()
{}
publicUploadSetInfo(stringattachExtensions,stringattachExtensionsNoSize,intmaxTodaySize,
intattachSize,boolcanPostAttach,intmaxAttachSize,stringerrMessage)
{
m_attachExtensions=attachExtensions;
m_attachExtensionsNoSize=attachExtensionsNoSize;
m_maxTodaySize=maxTodaySize;
m_attachSize=attachSize;
m_canPostAttach=canPostAttach;
m_maxAttachSize=maxAttachSize;
m_errMessage=errMessage;
m_maxAttachments=GeneralConfigs.GetConfig().Maxattachments;
}
privatestringm_attachExtensions;
///<summary>
///用户可以上传的文件类型
///</summary>
publicstringAttachExtensions
{
get{returnm_attachExtensions;}
set{m_attachExtensions=value;}
}
privatestringm_attachExtensionsNoSize;
///<summary>
///用户可以上传的文件类型(不带上传数据大小)
///</summary>
publicstringAttachExtensionsNoSize
{
get{returnm_attachExtensionsNoSize;}
set{m_attachExtensionsNoSize=value;}
}
privateintm_maxTodaySize;
///<summary>
///得到今天允许用户上传的附件总大小(字节)
///</summary>
publicintMaxTodaySize
{
get{returnm_maxTodaySize;}
set{m_maxTodaySize=value;}
}
privateintm_attachSize;
///<summary>
///今天可上传的大小
///</summary>
publicintAttachSize
{
get{returnm_attachSize;}
set{m_attachSize=value;}
}
privateboolm_canPostAttach;
///<summary>
///是否允许上传附件
///</summary>
publicboolCanPostAttach
{
get{returnm_canPostAttach;}
set{m_canPostAttach=value;}
}
privateintm_maxAttachSize;
///<summary>
///单个附件大小
///</summary>
publicintMaxAttachSize
{
get{returnm_maxAttachSize;}
set{m_maxAttachSize=value;}
}
privatestringm_errMessage;
///<summary>
///错误信息
///</summary>
publicstringErrMessage
{
get{returnm_errMessage;}
set{m_errMessage=value;}
}
privateintm_maxAttachments;
///<summary>
///最大允许上传的附件数
///</summary>
publicintMaxattachments
{
get{returnm_maxAttachments;}
set{m_maxAttachments=value;}
}
}
#endregion
如果一切顺利,客户端会获取相应的UploadSetInfo实例信息来进行SL插件的信息绑定,也就是之前第
二张图中所说的信息内容(红框部分)。
如果当前用户通过验证,就可以通过SL上传附件了,因为用户上传的附件要进行实时统计,以即时更新
已上传附件的总和大小,来防止用户上传过量的附件),所以我在打开文件对话框事件中加入了到已上传
附件大小的统计以便进行控件:
///选择文件对话框事件
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatevoidSelectFilesButton_Click(objectsender,RoutedEventArgse)
{
if(AttachmentList.Count>=_maxAttachments)
{
ShowMessageBox("\r\n您上传的文件数已达到系统规定的上限:"+_maxAttachments+".");
return;
}
OpenFileDialogofd=newOpenFileDialog();
ofd.Multiselect=true;
try
{
if(!string.IsNullOrEmpty(_fileFilter))
ofd.Filter=_fileFilter;
}
catch(ArgumentExceptionex)
{
ShowMessageBox("错误的文件过滤配置:"+ex.Message);
}
if(ofd.ShowDialog()==true)
{
if(filecount==0)
filecount=AttachmentList.Count;
foreach(FileInfofileinofd.Files)
{
if((filecount+1)>_maxAttachments)
{
ShowMessageBox("\r\n您上传的文件数已达到系统规定的上限:"+_maxAttachments+".");
return;
}
filecount++;
stringfileName=file.Name;
UserFileuserFile=newUserFile();
userFile.FileName=file.Name;
userFile.FileStream=file.OpenRead();
userFile.ViewStream=file.OpenRead();
//总上传值在规定范围内时
if(_todayAttachSize<(_todayUploadSize+_wantUploadSize+userFile.FileStream.Length))
{
ShowMessageBox("\r\n当前附件大小:"+Math.Round((decimal)userFile.FileStream.Length/1024/1024,2)
+"MB,而今天还可以上传:"+Math.Round((decimal)(_todayAttachSize-_todayUploadSize)/1024/1024,2)+"MB.");
break;
}
//当单个文件大小大于最大上传附件尺寸时
if(userFile.FileStream.Length>_maxFileSize)
{
ShowMessageBox("\r\n当前附件大小:"+Math.Round((decimal)userFile.FileStream.Length/1024/1024,2)
+"MB,而单个附件允许最大尺寸为:"+Math.Round((decimal)_maxFileSize/1024/1024,2)+"MB.\r\n");
break;
}
//向文件列表中添加文件信息
_files.Add(userFile);
_wantUploadSize+=userFile.FileStream.Length;
}
}
}
这样就从选择附件方面杜绝了上述情况的发生。
之后,当用户选择了上传的附件,并加载到上传列表后点击上传按钮时,SL会将当前要上传的文件进行
切块(4 * 4096 byte),并分块上传,代码如下:
///上传文件
///</summary>
privatevoidUploadAdvanced()
{
byte[]buffer=newbyte[4*4096];
intbytesRead=_file.FileStream.Read(buffer,0,buffer.Length);
//文件是否上传完毕?
if(bytesRead!=0)
{
_dataSent+=bytesRead;
if(_dataSent==_dataLength)
_lastChunk=true;//是否是最后一块数据,这样WCF会在服务端根据该信息来决定是否对临时文件重命名
//上传当前数据块
_client.StoreFileAdvancedAsync(_file.FileName,buffer,bytesRead,_initParams,_firstChunk,_lastChunk,
Utils.GetCredentialInfo());
//在第一条消息之后一直为false
_firstChunk=false;
//通知上传进度修改
OnProgressChanged();
}
else
{
//当上传完毕后
_file.FileStream.Dispose();
_file.FileStream.Close();
_client.ChannelFactory.Close();
}
}
注意上面的StoreFileAdvancedAsync方法就是要请求的服务端代码,下面即是其服务端代码:
///上传附件
///</summary>
///<paramname="fileName">文件名称</param>
///<paramname="data">上传的字节数据</param>
///<paramname="dataLength">数据长度</param>
///<paramname="parameters">上传参数</param>
///<paramname="firstChunk">是否第一块数据</param>
///<paramname="lastChunk">是否最后一块数据</param>
[WebMethod]
publicAttachmentInfoStoreFileAdvanced(stringfileName,byte[]data,intdataLength,stringparameters,
boolfirstChunk,boollastChunk,CredentialInfocreinfo)
{
if(AuthenticateUser(creinfo))
{
UploadSetInfouploadSetInfo=GetAttachmentUploadSet(creinfo);
stringfileextname=Utils.CutString(fileName,fileName.LastIndexOf(".")+1).ToLower();
if(uploadSetInfo.CanPostAttach&&uploadSetInfo.AttachExtensionsNoSize.IndexOf(fileextname)>=0&&
uploadSetInfo.AttachSize>dataLength&&Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))
{
stringuploadFolder=GetUploadFolder(fileName,creinfo.ForumID.ToString());
stringtempFileName=fileName+_tempExtension;
if(firstChunk)
{
//删除临时文件
if(File.Exists(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName))
File.Delete(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName);
//删除目录文件
if(File.Exists(uploadFolder+"/"+fileName))
File.Delete(uploadFolder+"/"+fileName);
}
FileStreamfs=File.Open(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+
tempFileName,FileMode.Append);
fs.Write(data,0,dataLength);
fs.Close();
if(lastChunk)
{
File.Move(HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName,
uploadFolder+"/"+fileName);
returnDiscuz.Forum.Attachments.GetAttachmentInfo(AddAttachment(fileName,creinfo));
}
}
}
returnnull;
}
上面代码会将客户端发送过来的分块数据进行组装到临时文件中,当该文件的所有分块数据传输完毕,
就会将该临时文件移动到指定的附件文件夹中,同时删除相应临时数据。大家注意到了,在该方法开始部分
还调用了AuthenticateUser方法(之前说明),这主要就是对安全性的考虑,必定HTTP是一种无状态协议呀。
上面的代码中这一行判断:
&&uploadSetInfo.AttachSize>dataLength&&
Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))
即是对当前用户上传信息(包括已上传附件大小,数量等)进行检验,以免出现上传数据超过系统限制
的情况。
在该方法的最后一行,会调用AddAttachment(fileName, creinfo)来进行相应附件信息的初始化绑定,
因为论坛中每个主题包括回帖都可以有附件,只不过对附件的扩展名和大小会有限制,所以这里通过该方法
进行封装,下面是其核心代码:
///添加附件
///</summary>
///<paramname="fileName">文件名称</param>
///<paramname="creinfo">认证信息</param>
///<returns>返回当前插入的附件id</returns>
privateintAddAttachment(stringfileName,CredentialInfocreinfo)
{
stringUploadDir=GetUploadFolder(fileName,creinfo.ForumID.ToString());
AttachmentInfoattachmentinfo=newAttachmentInfo();
stringfileextname=Utils.CutString(fileName,fileName.LastIndexOf(".")+1).ToLower();
stringnewfilename=(Environment.TickCount&int.MaxValue).ToString()+newRandom().Next(1000,9999)
+"."+fileextname;
try
{
//如果是bmpjpgpng图片类型
if((fileextname=="bmp"||fileextname=="jpg"||fileextname=="jpeg"||fileextname=="png"))
{
if(Discuz.Common.Utils.FileExists(UploadDir+fileName))
{
System.Drawing.Imageimg=System.Drawing.Image.FromFile(UploadDir+fileName);
if(config.Attachimgmaxwidth>0&&img.Width>config.Attachimgmaxwidth)
attachmentinfo.Sys_noupload="图片宽度为"+img.Width.ToString()+",系统允许的最大宽度为"
+config.Attachimgmaxwidth.ToString();
if(config.Attachimgmaxheight>0&&img.Height>config.Attachimgmaxheight)
attachmentinfo.Sys_noupload="图片高度为"+img.Width.ToString()+",系统允许的最大高度为"
+config.Attachimgmaxheight.ToString();
if(config.Watermarkstatus==0)
attachmentinfo.Filesize=newFileInfo(UploadDir+fileName).Length;
else
{
if(config.Watermarktype==1&&File.Exists(Utils.GetMapPath(BaseConfigs.GetForumPath
+"watermark/"+config.Watermarkpic)))
Discuz.Forum.ForumUtils.AddImageSignPic(img,UploadDir+newfilename,
Utils.GetMapPath(BaseConfigs.GetForumPath+"watermark/"+config.Watermarkpic),
config.Watermarkstatus,config.Attachimgquality,config.Watermarktransparency);
else
{
stringwatermarkText;
watermarkText=config.Watermarktext.Replace("{1}",config.Forumtitle);
watermarkText=watermarkText.Replace("{2}",""+DNTRequest.GetCurrentFullHost()+"/");
watermarkText=watermarkText.Replace("{3}",Utils.GetDate());
watermarkText=watermarkText.Replace("{4}",Utils.GetTime());
Discuz.Forum.ForumUtils.AddImageSignText(img,UploadDir+newfilename,watermarkText,
config.Watermarkstatus,config.Attachimgquality,config.Watermarkfontname,config.Watermarkfontsize);
}
System.IO.File.Delete(UploadDir+fileName);
//获得加水印后的文件长度
attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;
}
}
}
else
{
System.IO.File.Move(UploadDir+fileName,UploadDir+newfilename);
attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;
}
}
catch{}
if(Discuz.Common.Utils.FileExists(UploadDir+fileName))
{
attachmentinfo.Filesize=newFileInfo(UploadDir+fileName).Length;
attachmentinfo.Filename=GetDirInfo(fileName,creinfo.ForumID.ToString())+fileName;
}
if(Discuz.Common.Utils.FileExists(UploadDir+newfilename))
{
attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;
attachmentinfo.Filename=GetDirInfo(newfilename,creinfo.ForumID.ToString())+newfilename;
}
attachmentinfo.Uid=creinfo.UserID;
attachmentinfo.Description=fileextname;
attachmentinfo.Filetype=GetContentType(fileextname);
attachmentinfo.Attachment=fileName;
attachmentinfo.Downloads=0;
attachmentinfo.Postdatetime=DateTime.Now.ToString();
attachmentinfo.Sys_index=0;
returnDiscuz.Data.DatabaseProvider.GetInstance().CreateAttachment(attachmentinfo);
}
通过上面的方法就实现了将附件与相应的主题进行绑定功能同时为相应的图片附件加上水印。
到这里,主要的代码就介绍的差不多了。
当用户完成上传之后,点击“返回”按钮时,会触发下面事件:
///返回按钮事件
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatevoidFinishUpload_Click(objectsender,RoutedEventArgse)
{
GetAttachmentList();
}
[ScriptableMember]
publicvoidGetAttachmentList()
{
StringBuildersb_attachments=newStringBuilder();
sb_attachments.Append("[");
foreach(AttachmentInfoattachmentInfoinAttachmentList)
{
sb_attachments.Append(string.Format("{{'aid':{0},'attachment':'{1}','description':'{2}','filename':
'{3}','filesize':{4},'filetype':'{5}','Uid':{6}}},",
attachmentInfo.Aid,
attachmentInfo.Attachment,
attachmentInfo.Description.Trim(),
attachmentInfo.Filename.Trim(),
attachmentInfo.Filesize,
attachmentInfo.Filetype,
attachmentInfo.Uid
));
}
if(sb_attachments.ToString().EndsWith(","))
sb_attachments.Remove(sb_attachments.Length-1,1);
sb_attachments.Append("]");
//调用js端注册事件
javaScriptableObject.OnUploadAttchmentList(JsonCharFilter(sb_attachments.ToString()));
}
GetAttachmentList方法会调用页面的JS事件并将“已上传”的数据发给WEB页面,而相应的页面
事件绑定代码如下(文件位于Discuz.Web\templates\default_postattachments.htm):
//只读属性,标识Silverlight插件是否已经加载。
if(sender.getHost().IsLoaded){
$("MultiUploadFile").content.JavaScriptObject.UploadAttchmentList=getAttachmentList;
}
}
//获取silverlight插件已经上传的附件列表
functiongetAttachmentList(sender,args){
varattachment=args.AttchmentList;
if(isUndefined(attachment)||attachment=='[]'){
BOX_remove('silverlightControlHost');
return;
}
varattachmentList=eval("("+attachment+")");
BOX_remove('silverlightControlHost');
addAttachUploaded(attachmentList);
}
这样一个SL多文件上传插件就算基本完成了。当然我还写了“缩略图”功能,因为代码很简单就不
多说了。
好了,今天的内容就先到这里了。
原文链接: www.cnblogs.com/daizhj/archive/2009/04/07/1431090.html
作者: daizhj, 代震军
Tags: silverlight,discuznt,uploadfile,文件上传
网址: daizhj.cnblogs.com/
本文共计4723个文字,预计阅读时间需要19分钟。
注意:原文的HTML页面位置依赖于Discuz.Web项目,具体位置请参考官方文档。以下是一篇关于推荐一个Silverlight多文件(大文件)上传开源项目的文章:
《推荐一个Silverlight多文件(大文件)上传开源项目》
近年来,随着互联网技术的飞速发展,大文件上传的需求日益增长。为了满足这一需求,本文将推荐一个基于Silverlight的多文件上传开源项目。
该项目名为Silverlight Multi-File Upload,是一款功能强大的Silverlight客户端应用程序,旨在实现大文件的高效上传。以下是该项目的几个亮点:
1. 支持多文件选择,用户可以一次性上传多个文件。
2.支持大文件上传,单个文件大小可达数GB。
3.采用分片上传技术,提高上传速度和稳定性。
4.支持断点续传,确保上传过程中不会因为网络问题导致上传中断。
5.开源免费,可自由修改和二次开发。
使用该项目的步骤如下:
1. 下载项目源码。
2.将项目导入到Visual Studio中。
3.修改配置文件,设置服务器端上传地址等信息。
4.运行项目,进行测试。
总结:Silverlight Multi-File Upload项目是一款优秀的开源多文件上传工具,适用于各种大文件上传场景。希望本文的推荐对您有所帮助。
注:本文的HTM页面均位于Discuz.Web项目中,大家可以到官方下面最终的程序。
在去年我曾写过一篇文章:“推荐一个Silverlight多文件(大文件)上传的开源项目”。之后
有不少朋友询问这个项目示例在开发和配置上的一些问题。当时因为时间有限没有做过多的说明,
导致有些问题在大家下载完源码之后运行时才出现。今天就以这个项目为原型,简要介绍一下在
DiscuzNT上是如果在该项目基本上,通过完善权限管理,文件大小控制,添加缩略图效果等功能
来大体阐述一下如果开发一个真正的silverlight应用,而不是一个简单的DEMO.
当然本文中所列出的源码是通过reflector获取并添加相应注释的。最终的源码还是要以开放
出来的为准,呵呵:)
好了,开始今天的正文吧!
首先,看一下这个插件在DiscuzNT中的实际运行效果:
当我们在网页中点击“批量上传”按钮时,会运行如下JS脚本(文件位于Discuz.Web\
templates\default_postattachments.htm):
Silverlight.createObject(
"silverlight/UploadFile/ClientBin/MultiFileUpload.xap",
$("silverlightControlHost"),
pluginID,
{
width:'500',
height:'440',
inplaceInstallPrompt:'true',
isWindowless:'true',
background:'transparent',
version:'2.0',
autoUpgrade:'true'
},
{
onLoad:onLoad,
onError:onSilverlightError
},
<%csharp%>
stringauthToken=Discuz.Common.DES.Encode(oluserinfo.Olid.ToString()+","+
oluserinfo.Username.ToString(),oluserinfo.Password.Substring(0,10)).Replace("+","[");
<%/csharp%>
"forumid={forumid},authToken={authToken},max="+max,
"");
}
其会将当前版块id(forumid),认证Token,最大上传数等信息以参数形式传给SL插件,而我专门定
义了一个方法用于获取相应的参数并绑定到sl变量,如下(Page.xaml.cs):
///加载配置参数
///</summary>
///<paramname="initParams"></param>
privatevoidLoadConfiguration(IDictionary<string,string>initParams)
{
stringtryTest=string.Empty;
//加载定制配置信息串
_customParams=initParams["forumid"];
if(initParams.ContainsKey("MaxUploads")&&!string.IsNullOrEmpty(initParams["MaxUploads"]))
int.TryParse(initParams["MaxUploads"],out_maxUpload);
if(initParams.ContainsKey("MaxFileSizeKB")&&!string.IsNullOrEmpty(initParams["MaxFileSizeKB"]))
{
if(int.TryParse(initParams["MaxFileSizeKB"],out_maxFileSize))
_maxFileSize=_maxFileSize*1024;
}
if(initParams.ContainsKey("FileFilter")&&!string.IsNullOrEmpty(initParams["FileFilter"]))
_fileFilter=initParams["FileFilter"];
if(initParams.ContainsKey("forumid")&&!string.IsNullOrEmpty(initParams["forumid"]))
_forumid=Utils.StrToInt(initParams["forumid"],0);
if(initParams.ContainsKey("max")&&!string.IsNullOrEmpty(initParams["max"]))
_maxAttachments=Utils.StrToInt(initParams["max"],0);
CredentialInfo_creInfo=Utils.GetCredentialInfo();
if(_creInfo.UserID<=0)
{
ShowMessageBox("您未登陆系统");
SetUploadButton(false);
return;
}
else
{
MixObjectsSoapClient_client=Utils.CreateServiceClient();
_client.GetAttachmentUploadSetCompleted+=newEventHandler<GetAttachmentUploadSetCompletedEventArgs>
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo,_forumid);
}
}
大家看到在该方法在获取相应初始化参数(initParams)后,会调用Utils.GetCredentialInfo()来获取
用户登陆信息:
///获取认证信息
///</summary>
///<returns></returns>
publicstaticCredentialInfoGetCredentialInfo()
{
CredentialInfo_creinfo=newCredentialInfo();
_creinfo.UserID=Utils.StrToInt(Utils.GetCookie("userid"),0);
_creinfo.Password=Utils.GetCookie("password");
if(App.GetInitParmas.ContainsKey("authToken")&&!string.IsNullOrEmpty(App.GetInitParmas["authToken"]))
_creinfo.AuthToken=App.GetInitParmas["authToken"];
if(App.GetInitParmas.ContainsKey("forumid")&&!string.IsNullOrEmpty(App.GetInitParmas["forumid"]))
_creinfo.ForumID=StrToInt(App.GetInitParmas["forumid"],0);
return_creinfo;
}
其中最主要的就是获取相应的UserID,而这个操作是交给GetCookie来完成的:
{
if(string.IsNullOrEmpty(HtmlPage.Document.Cookies))
returnnull;
//找到想应的cookie键值
stringresult=(fromcin
(fromcookieinHtmlPage.Document.Cookies.Split(';')
wherecookie.Contains(key+"=")
selectcookie.Split('&')).FirstOrDefault()
wherec.Contains(key+"=")
selectc).FirstOrDefault().ToString();
if(string.IsNullOrEmpty(result))
returnnull;
returnresult.Substring(result.IndexOf(key+"=")+key.Length+1);
}
其主要是通过用户本地的Cookie,来获取相应的用户信息。
如果用户的Cookie有效(已登陆过),则直接获取该用户所在用户组及其它相关联的权限信息,
如果无效,则提示用户登陆,同时将SL中的几个上传按钮“置灰”,以免未登陆的用户上传附件。
下面就是其向服务器请求谁信息的代码:
_client.GetAttachmentUploadSetCompleted+=newEventHandler<GetAttachmentUploadSetCompletedEventArgs>
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo,_forumid);
上面客户端请求下面的服务端代码:
///通过指定用户认证信息来获得该用户的上传设置信息
///</summary>
///<paramname="creinfo">用户认证信息</param>
///<returns></returns>
[WebMethod]
publicUploadSetInfoGetAttachmentUploadSet(CredentialInfocreinfo)
{
if(AuthenticateUser(creinfo))
{
UserInfouserinfo=Discuz.Forum.Users.GetUserInfo(creinfo.UserID);
if(userinfo==null)
returnnewUploadSetInfo("","",0,0,false,0,"当前用户信息无效,请尝试刷新");
UserGroupInfousergroupinfo=Discuz.Forum.UserGroups.GetUserGroupInfo(userinfo.Groupid);
if(usergroupinfo==null)
returnnewUploadSetInfo("","",0,0,false,0,"当前用户所属用户组信息无效");
ForumInfoforum=Discuz.Forum.Forums.GetForumInfo(creinfo.ForumID);
if(forum==null)
returnnewUploadSetInfo(null,null,0,0,false,0,"当前版块信息无效,请尝试刷新");
//得到用户可以上传的文件类型
StringBuildersbAttachmentTypeSelect=newStringBuilder();
if(!usergroupinfo.Attachextensions.Trim().Equals(""))
{
sbAttachmentTypeSelect.Append("[id]in(");
sbAttachmentTypeSelect.Append(usergroupinfo.Attachextensions);
sbAttachmentTypeSelect.Append(")");
}
if(!forum.Attachextensions.Equals(""))
{
if(sbAttachmentTypeSelect.Length>0)
sbAttachmentTypeSelect.Append("AND");
sbAttachmentTypeSelect.Append("[id]in(");
sbAttachmentTypeSelect.Append(forum.Attachextensions);
sbAttachmentTypeSelect.Append(")");
}
stringattachextensions=Discuz.Forum.Attachments.GetAttachmentTypeArray(sbAttachmentTypeSelect.ToString());
stringattachextensionsnosize=Discuz.Forum.Attachments.GetAttachmentTypeString(sbAttachmentTypeSelect.ToString());
//得到今天允许用户上传的附件总大小(字节)
intMaxTodaySize=0;
if(creinfo.UserID>0)
MaxTodaySize=Discuz.Forum.Attachments.GetUploadFileSizeByuserid(creinfo.UserID);
intattachsize=usergroupinfo.Maxsizeperday-MaxTodaySize;//今天可上传大小
boolcanpostattach=false;//是否允许上传附件
//是否有上传附件的权限
if(Discuz.Forum.Forums.AllowPostAttachByUserID(forum.Permuserlist,creinfo.UserID))
canpostattach=true;
else
{
if(forum.Postattachperm=="")
{
if(usergroupinfo.Allowpostattach==1)
canpostattach=true;
}
else
{
if(Discuz.Forum.Forums.AllowPostAttach(forum.Postattachperm,usergroupinfo.Groupid))
canpostattach=true;
}
}
returnnewUploadSetInfo(attachextensions,attachextensionsnosize,MaxTodaySize,attachsize,
canpostattach,usergroupinfo.Maxattachsize,"");
}
returnnewUploadSetInfo("","",0,0,false,0,"当前用户信息无效,请尝试刷新");
}
该方法的首先会访问AuthenticateUser方法来进行用户身份验证:
/// <summary>
/// WEB权限认证
///<paramname="creinfo">认证信息</param>
///<returns>是否通过验正</returns>
privateboolAuthenticateUser(CredentialInfocreinfo)
{
if(creinfo.ForumID>0)
{
intolid=Discuz.Forum.OnlineUsers.GetOlidByUid(creinfo.UserID);
if(olid>0)
{
OnlineUserInfooluserinfo=Discuz.Forum.OnlineUsers.GetOnlineUser(olid);
if(oluserinfo.Userid==creinfo.UserID&&
Utils.UrlEncode(Discuz.Forum.ForumUtils.SetCookiePassword(oluserinfo.Password,
GeneralConfigs.GetConfig().Passwordkey))==creinfo.Password&&//检测用户id和口令
creinfo.AuthToken==DES.Encode(string.Format("{0},{1}",oluserinfo.Olid.ToString(),
oluserinfo.Username.ToString()),oluserinfo.Password.Substring(0,10)).Replace("+","["))//检查认证信息
{
returntrue;
}
}
}
returnfalse;
}
其会对用户的UserId与用户在线表中的数据进行比对,以确保其信息有效,同时还会检查AuthToken
来避免用户通过伪造用户信息来进行信息提交。当上面方法返回TRUE时,则将对用户所在版块的权限信息
进行获取,并返回一个名为UploadSetInfo类实例,其包括:
2.用户可以上传的文件类型(不带上传数据大小)
3.得到今天允许用户上传的附件总大小(字节)
4.是否允许上传附件
5.单个附件大小
6.最大允许上传的附件数
7.错误信息 #region上传设置信息类
///<summary>
///上传设置信息类
///</summary>
publicclassUploadSetInfo
{
publicUploadSetInfo()
{}
publicUploadSetInfo(stringattachExtensions,stringattachExtensionsNoSize,intmaxTodaySize,
intattachSize,boolcanPostAttach,intmaxAttachSize,stringerrMessage)
{
m_attachExtensions=attachExtensions;
m_attachExtensionsNoSize=attachExtensionsNoSize;
m_maxTodaySize=maxTodaySize;
m_attachSize=attachSize;
m_canPostAttach=canPostAttach;
m_maxAttachSize=maxAttachSize;
m_errMessage=errMessage;
m_maxAttachments=GeneralConfigs.GetConfig().Maxattachments;
}
privatestringm_attachExtensions;
///<summary>
///用户可以上传的文件类型
///</summary>
publicstringAttachExtensions
{
get{returnm_attachExtensions;}
set{m_attachExtensions=value;}
}
privatestringm_attachExtensionsNoSize;
///<summary>
///用户可以上传的文件类型(不带上传数据大小)
///</summary>
publicstringAttachExtensionsNoSize
{
get{returnm_attachExtensionsNoSize;}
set{m_attachExtensionsNoSize=value;}
}
privateintm_maxTodaySize;
///<summary>
///得到今天允许用户上传的附件总大小(字节)
///</summary>
publicintMaxTodaySize
{
get{returnm_maxTodaySize;}
set{m_maxTodaySize=value;}
}
privateintm_attachSize;
///<summary>
///今天可上传的大小
///</summary>
publicintAttachSize
{
get{returnm_attachSize;}
set{m_attachSize=value;}
}
privateboolm_canPostAttach;
///<summary>
///是否允许上传附件
///</summary>
publicboolCanPostAttach
{
get{returnm_canPostAttach;}
set{m_canPostAttach=value;}
}
privateintm_maxAttachSize;
///<summary>
///单个附件大小
///</summary>
publicintMaxAttachSize
{
get{returnm_maxAttachSize;}
set{m_maxAttachSize=value;}
}
privatestringm_errMessage;
///<summary>
///错误信息
///</summary>
publicstringErrMessage
{
get{returnm_errMessage;}
set{m_errMessage=value;}
}
privateintm_maxAttachments;
///<summary>
///最大允许上传的附件数
///</summary>
publicintMaxattachments
{
get{returnm_maxAttachments;}
set{m_maxAttachments=value;}
}
}
#endregion
如果一切顺利,客户端会获取相应的UploadSetInfo实例信息来进行SL插件的信息绑定,也就是之前第
二张图中所说的信息内容(红框部分)。
如果当前用户通过验证,就可以通过SL上传附件了,因为用户上传的附件要进行实时统计,以即时更新
已上传附件的总和大小,来防止用户上传过量的附件),所以我在打开文件对话框事件中加入了到已上传
附件大小的统计以便进行控件:
///选择文件对话框事件
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatevoidSelectFilesButton_Click(objectsender,RoutedEventArgse)
{
if(AttachmentList.Count>=_maxAttachments)
{
ShowMessageBox("\r\n您上传的文件数已达到系统规定的上限:"+_maxAttachments+".");
return;
}
OpenFileDialogofd=newOpenFileDialog();
ofd.Multiselect=true;
try
{
if(!string.IsNullOrEmpty(_fileFilter))
ofd.Filter=_fileFilter;
}
catch(ArgumentExceptionex)
{
ShowMessageBox("错误的文件过滤配置:"+ex.Message);
}
if(ofd.ShowDialog()==true)
{
if(filecount==0)
filecount=AttachmentList.Count;
foreach(FileInfofileinofd.Files)
{
if((filecount+1)>_maxAttachments)
{
ShowMessageBox("\r\n您上传的文件数已达到系统规定的上限:"+_maxAttachments+".");
return;
}
filecount++;
stringfileName=file.Name;
UserFileuserFile=newUserFile();
userFile.FileName=file.Name;
userFile.FileStream=file.OpenRead();
userFile.ViewStream=file.OpenRead();
//总上传值在规定范围内时
if(_todayAttachSize<(_todayUploadSize+_wantUploadSize+userFile.FileStream.Length))
{
ShowMessageBox("\r\n当前附件大小:"+Math.Round((decimal)userFile.FileStream.Length/1024/1024,2)
+"MB,而今天还可以上传:"+Math.Round((decimal)(_todayAttachSize-_todayUploadSize)/1024/1024,2)+"MB.");
break;
}
//当单个文件大小大于最大上传附件尺寸时
if(userFile.FileStream.Length>_maxFileSize)
{
ShowMessageBox("\r\n当前附件大小:"+Math.Round((decimal)userFile.FileStream.Length/1024/1024,2)
+"MB,而单个附件允许最大尺寸为:"+Math.Round((decimal)_maxFileSize/1024/1024,2)+"MB.\r\n");
break;
}
//向文件列表中添加文件信息
_files.Add(userFile);
_wantUploadSize+=userFile.FileStream.Length;
}
}
}
这样就从选择附件方面杜绝了上述情况的发生。
之后,当用户选择了上传的附件,并加载到上传列表后点击上传按钮时,SL会将当前要上传的文件进行
切块(4 * 4096 byte),并分块上传,代码如下:
///上传文件
///</summary>
privatevoidUploadAdvanced()
{
byte[]buffer=newbyte[4*4096];
intbytesRead=_file.FileStream.Read(buffer,0,buffer.Length);
//文件是否上传完毕?
if(bytesRead!=0)
{
_dataSent+=bytesRead;
if(_dataSent==_dataLength)
_lastChunk=true;//是否是最后一块数据,这样WCF会在服务端根据该信息来决定是否对临时文件重命名
//上传当前数据块
_client.StoreFileAdvancedAsync(_file.FileName,buffer,bytesRead,_initParams,_firstChunk,_lastChunk,
Utils.GetCredentialInfo());
//在第一条消息之后一直为false
_firstChunk=false;
//通知上传进度修改
OnProgressChanged();
}
else
{
//当上传完毕后
_file.FileStream.Dispose();
_file.FileStream.Close();
_client.ChannelFactory.Close();
}
}
注意上面的StoreFileAdvancedAsync方法就是要请求的服务端代码,下面即是其服务端代码:
///上传附件
///</summary>
///<paramname="fileName">文件名称</param>
///<paramname="data">上传的字节数据</param>
///<paramname="dataLength">数据长度</param>
///<paramname="parameters">上传参数</param>
///<paramname="firstChunk">是否第一块数据</param>
///<paramname="lastChunk">是否最后一块数据</param>
[WebMethod]
publicAttachmentInfoStoreFileAdvanced(stringfileName,byte[]data,intdataLength,stringparameters,
boolfirstChunk,boollastChunk,CredentialInfocreinfo)
{
if(AuthenticateUser(creinfo))
{
UploadSetInfouploadSetInfo=GetAttachmentUploadSet(creinfo);
stringfileextname=Utils.CutString(fileName,fileName.LastIndexOf(".")+1).ToLower();
if(uploadSetInfo.CanPostAttach&&uploadSetInfo.AttachExtensionsNoSize.IndexOf(fileextname)>=0&&
uploadSetInfo.AttachSize>dataLength&&Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))
{
stringuploadFolder=GetUploadFolder(fileName,creinfo.ForumID.ToString());
stringtempFileName=fileName+_tempExtension;
if(firstChunk)
{
//删除临时文件
if(File.Exists(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName))
File.Delete(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName);
//删除目录文件
if(File.Exists(uploadFolder+"/"+fileName))
File.Delete(uploadFolder+"/"+fileName);
}
FileStreamfs=File.Open(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+
tempFileName,FileMode.Append);
fs.Write(data,0,dataLength);
fs.Close();
if(lastChunk)
{
File.Move(HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName,
uploadFolder+"/"+fileName);
returnDiscuz.Forum.Attachments.GetAttachmentInfo(AddAttachment(fileName,creinfo));
}
}
}
returnnull;
}
上面代码会将客户端发送过来的分块数据进行组装到临时文件中,当该文件的所有分块数据传输完毕,
就会将该临时文件移动到指定的附件文件夹中,同时删除相应临时数据。大家注意到了,在该方法开始部分
还调用了AuthenticateUser方法(之前说明),这主要就是对安全性的考虑,必定HTTP是一种无状态协议呀。
上面的代码中这一行判断:
&&uploadSetInfo.AttachSize>dataLength&&
Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))
即是对当前用户上传信息(包括已上传附件大小,数量等)进行检验,以免出现上传数据超过系统限制
的情况。
在该方法的最后一行,会调用AddAttachment(fileName, creinfo)来进行相应附件信息的初始化绑定,
因为论坛中每个主题包括回帖都可以有附件,只不过对附件的扩展名和大小会有限制,所以这里通过该方法
进行封装,下面是其核心代码:
///添加附件
///</summary>
///<paramname="fileName">文件名称</param>
///<paramname="creinfo">认证信息</param>
///<returns>返回当前插入的附件id</returns>
privateintAddAttachment(stringfileName,CredentialInfocreinfo)
{
stringUploadDir=GetUploadFolder(fileName,creinfo.ForumID.ToString());
AttachmentInfoattachmentinfo=newAttachmentInfo();
stringfileextname=Utils.CutString(fileName,fileName.LastIndexOf(".")+1).ToLower();
stringnewfilename=(Environment.TickCount&int.MaxValue).ToString()+newRandom().Next(1000,9999)
+"."+fileextname;
try
{
//如果是bmpjpgpng图片类型
if((fileextname=="bmp"||fileextname=="jpg"||fileextname=="jpeg"||fileextname=="png"))
{
if(Discuz.Common.Utils.FileExists(UploadDir+fileName))
{
System.Drawing.Imageimg=System.Drawing.Image.FromFile(UploadDir+fileName);
if(config.Attachimgmaxwidth>0&&img.Width>config.Attachimgmaxwidth)
attachmentinfo.Sys_noupload="图片宽度为"+img.Width.ToString()+",系统允许的最大宽度为"
+config.Attachimgmaxwidth.ToString();
if(config.Attachimgmaxheight>0&&img.Height>config.Attachimgmaxheight)
attachmentinfo.Sys_noupload="图片高度为"+img.Width.ToString()+",系统允许的最大高度为"
+config.Attachimgmaxheight.ToString();
if(config.Watermarkstatus==0)
attachmentinfo.Filesize=newFileInfo(UploadDir+fileName).Length;
else
{
if(config.Watermarktype==1&&File.Exists(Utils.GetMapPath(BaseConfigs.GetForumPath
+"watermark/"+config.Watermarkpic)))
Discuz.Forum.ForumUtils.AddImageSignPic(img,UploadDir+newfilename,
Utils.GetMapPath(BaseConfigs.GetForumPath+"watermark/"+config.Watermarkpic),
config.Watermarkstatus,config.Attachimgquality,config.Watermarktransparency);
else
{
stringwatermarkText;
watermarkText=config.Watermarktext.Replace("{1}",config.Forumtitle);
watermarkText=watermarkText.Replace("{2}",""+DNTRequest.GetCurrentFullHost()+"/");
watermarkText=watermarkText.Replace("{3}",Utils.GetDate());
watermarkText=watermarkText.Replace("{4}",Utils.GetTime());
Discuz.Forum.ForumUtils.AddImageSignText(img,UploadDir+newfilename,watermarkText,
config.Watermarkstatus,config.Attachimgquality,config.Watermarkfontname,config.Watermarkfontsize);
}
System.IO.File.Delete(UploadDir+fileName);
//获得加水印后的文件长度
attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;
}
}
}
else
{
System.IO.File.Move(UploadDir+fileName,UploadDir+newfilename);
attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;
}
}
catch{}
if(Discuz.Common.Utils.FileExists(UploadDir+fileName))
{
attachmentinfo.Filesize=newFileInfo(UploadDir+fileName).Length;
attachmentinfo.Filename=GetDirInfo(fileName,creinfo.ForumID.ToString())+fileName;
}
if(Discuz.Common.Utils.FileExists(UploadDir+newfilename))
{
attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;
attachmentinfo.Filename=GetDirInfo(newfilename,creinfo.ForumID.ToString())+newfilename;
}
attachmentinfo.Uid=creinfo.UserID;
attachmentinfo.Description=fileextname;
attachmentinfo.Filetype=GetContentType(fileextname);
attachmentinfo.Attachment=fileName;
attachmentinfo.Downloads=0;
attachmentinfo.Postdatetime=DateTime.Now.ToString();
attachmentinfo.Sys_index=0;
returnDiscuz.Data.DatabaseProvider.GetInstance().CreateAttachment(attachmentinfo);
}
通过上面的方法就实现了将附件与相应的主题进行绑定功能同时为相应的图片附件加上水印。
到这里,主要的代码就介绍的差不多了。
当用户完成上传之后,点击“返回”按钮时,会触发下面事件:
///返回按钮事件
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatevoidFinishUpload_Click(objectsender,RoutedEventArgse)
{
GetAttachmentList();
}
[ScriptableMember]
publicvoidGetAttachmentList()
{
StringBuildersb_attachments=newStringBuilder();
sb_attachments.Append("[");
foreach(AttachmentInfoattachmentInfoinAttachmentList)
{
sb_attachments.Append(string.Format("{{'aid':{0},'attachment':'{1}','description':'{2}','filename':
'{3}','filesize':{4},'filetype':'{5}','Uid':{6}}},",
attachmentInfo.Aid,
attachmentInfo.Attachment,
attachmentInfo.Description.Trim(),
attachmentInfo.Filename.Trim(),
attachmentInfo.Filesize,
attachmentInfo.Filetype,
attachmentInfo.Uid
));
}
if(sb_attachments.ToString().EndsWith(","))
sb_attachments.Remove(sb_attachments.Length-1,1);
sb_attachments.Append("]");
//调用js端注册事件
javaScriptableObject.OnUploadAttchmentList(JsonCharFilter(sb_attachments.ToString()));
}
GetAttachmentList方法会调用页面的JS事件并将“已上传”的数据发给WEB页面,而相应的页面
事件绑定代码如下(文件位于Discuz.Web\templates\default_postattachments.htm):
//只读属性,标识Silverlight插件是否已经加载。
if(sender.getHost().IsLoaded){
$("MultiUploadFile").content.JavaScriptObject.UploadAttchmentList=getAttachmentList;
}
}
//获取silverlight插件已经上传的附件列表
functiongetAttachmentList(sender,args){
varattachment=args.AttchmentList;
if(isUndefined(attachment)||attachment=='[]'){
BOX_remove('silverlightControlHost');
return;
}
varattachmentList=eval("("+attachment+")");
BOX_remove('silverlightControlHost');
addAttachUploaded(attachmentList);
}
这样一个SL多文件上传插件就算基本完成了。当然我还写了“缩略图”功能,因为代码很简单就不
多说了。
好了,今天的内容就先到这里了。
原文链接: www.cnblogs.com/daizhj/archive/2009/04/07/1431090.html
作者: daizhj, 代震军
Tags: silverlight,discuznt,uploadfile,文件上传
网址: daizhj.cnblogs.com/

