注:本文的HTM页面均位于Discuz.Web项目中,大家可以到官方下面最终的程序。
在去年我曾写过一篇文章:“推荐一个Silverlight多文件(大文件)上传的开源项目”。之后
有不少朋友询问这个项目示例在开发和配置上的一些问题。当时因为时间有限没有做过多的说明,
导致有些问题在大家下载完源码之后运行时才出现。今天就以这个项目为原型,简要介绍一下在
DiscuzNT上是如果在该项目基本上,通过完善权限管理,文件大小控制,添加缩略图效果等功能
来大体阐述一下如果开发一个真正的silverlight应用,而不是一个简单的DEMO.
当然本文中所列出的源码是通过reflector获取并添加相应注释的。最终的源码还是要以开放
出来的为准,呵呵:)
好了,开始今天的正文吧!
首先,看一下这个插件在DiscuzNT中的实际运行效果:
当我们在网页中点击“批量上传”按钮时,会运行如下JS脚本(文件位于Discuz.Web\
templates\default_postattachments.htm):
function
LoadSilverlight(pluginID, max) {
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
%>
string authToken
=
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>
///
加载配置参数
///
</summary>
///
<param name="initParams"></param>
private
void
LoadConfiguration(IDictionary
<
string
,
string
>
initParams)
{
string
tryTest
=
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
+=
new
EventHandler
<
GetAttachmentUploadSetCompletedEventArgs
>
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo, _forumid);
}
}
大家看到在该方法在获取相应初始化参数(initParams)后,会调用Utils.GetCredentialInfo()来获取
用户登陆信息:
///
<summary>
///
获取认证信息
///
</summary>
///
<returns></returns>
public
static
CredentialInfo GetCredentialInfo()
{
CredentialInfo _creinfo
=
new
CredentialInfo();
_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来完成的:
public
static
string
GetCookie(String key)
{
if
(
string
.IsNullOrEmpty(HtmlPage.Document.Cookies))
return
null
;
//
找到想应的cookie键值
string
result
=
(from c
in
(from cookie
in
HtmlPage.Document.Cookies.Split(
'
;
'
)
where
cookie.Contains(key
+
"
=
"
)
select cookie.Split(
'
&
'
)).FirstOrDefault()
where
c.Contains(key
+
"
=
"
)
select c).FirstOrDefault().ToString();
if
(
string
.IsNullOrEmpty(result))
return
null
;
return
result.Substring(result.IndexOf(key
+
"
=
"
)
+
key.Length
+
1
);
}
其主要是通过用户本地的Cookie,来获取相应的用户信息。
如果用户的Cookie有效(已登陆过),则直接获取该用户所在用户组及其它相关联的权限信息,
如果无效,则提示用户登陆,同时将SL中的几个上传按钮“置灰”,以免未登陆的用户上传附件。
下面就是其向服务器请求谁信息的代码:
MixObjectsSoapClient _client
=
Utils.CreateServiceClient();
_client.GetAttachmentUploadSetCompleted
+=
new
EventHandler
<
GetAttachmentUploadSetCompletedEventArgs
>
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo, _forumid);
上面客户端请求下面的服务端代码:
///
<summary>
///
通过指定用户认证信息来获得该用户的上传设置信息
///
</summary>
///
<param name="creinfo">
用户认证信息
</param>
///
<returns></returns>
[WebMethod]
public
UploadSetInfo GetAttachmentUploadSet(CredentialInfo creinfo)
{
if
(AuthenticateUser(creinfo))
{
UserInfo userinfo
=
Discuz.Forum.Users.GetUserInfo(creinfo.UserID);
if
(userinfo
==
null
)
return
new
UploadSetInfo(
""
,
""
,
0
,
0
,
false
,
0
,
"
当前用户信息无效,请尝试刷新
"
);
UserGroupInfo usergroupinfo
=
Discuz.Forum.UserGroups.GetUserGroupInfo(userinfo.Groupid);
if
(usergroupinfo
==
null
)
return
new
UploadSetInfo(
""
,
""
,
0
,
0
,
false
,
0
,
"
当前用户所属用户组信息无效
"
);
ForumInfo forum
=
Discuz.Forum.Forums.GetForumInfo(creinfo.ForumID);
if
(forum
==
null
)
return
new
UploadSetInfo(
null
,
null
,
0
,
0
,
false
,
0
,
"
当前版块信息无效,请尝试刷新
"
);
//
得到用户可以上传的文件类型
StringBuilder sbAttachmentTypeSelect
=
new
StringBuilder();
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(
"
)
"
);
}
string
attachextensions
=
Discuz.Forum.Attachments.GetAttachmentTypeArray(sbAttachmentTypeSelect.ToString());
string
attachextensionsnosize
=
Discuz.Forum.Attachments.GetAttachmentTypeString(sbAttachmentTypeSelect.ToString());
//
得到今天允许用户上传的附件总大小(字节)
int
MaxTodaySize
=
0
;
if
(creinfo.UserID
>
0
)
MaxTodaySize
=
Discuz.Forum.Attachments.GetUploadFileSizeByuserid(creinfo.UserID);
int
attachsize
=
usergroupinfo.Maxsizeperday
-
MaxTodaySize;
//
今天可上传大小
bool
canpostattach
=
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
;
}
}
return
new
UploadSetInfo(attachextensions, attachextensionsnosize, MaxTodaySize, attachsize,
canpostattach , usergroupinfo.Maxattachsize,
""
);
}
return
new
UploadSetInfo(
""
,
""
,
0
,
0
,
false
,
0
,
"
当前用户信息无效,请尝试刷新
"
);
}
该方法的首先会访问AuthenticateUser方法来进行用户身份验证:
/// <summary>
/// WEB权限认证
///
</summary>
///
<param name="creinfo">
认证信息
</param>
///
<returns>
是否通过验正
</returns>
private
bool
AuthenticateUser(CredentialInfo creinfo)
{
if
(creinfo.ForumID
>
0
)
{
int
olid
=
Discuz.Forum.OnlineUsers.GetOlidByUid(creinfo.UserID);
if
(olid
>
0
)
{
OnlineUserInfo oluserinfo
=
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(
"
+
"
,
"
[
"
))
//
检查认证信息
{
return
true
;
}
}
}
return
false
;
}
其会对用户的UserId与用户在线表中的数据进行比对,以确保其信息有效,同时还会检查AuthToken
来避免用户通过伪造用户信息来进行信息提交。当上面方法返回TRUE时,则将对用户所在版块的权限信息
进行获取,并返回一个名为UploadSetInfo类实例,其包括:
1.用户可以上传的文件类型
2.用户可以上传的文件类型(不带上传数据大小)
3.得到今天允许用户上传的附件总大小(字节)
4.是否允许上传附件
5.单个附件大小
6.最大允许上传的附件数
7.错误信息
#region
上传设置信息类
///
<summary>
///
上传设置信息类
///
</summary>
public
class
UploadSetInfo
{
public
UploadSetInfo()
{ }
public
UploadSetInfo(
string
attachExtensions,
string
attachExtensionsNoSize,
int
maxTodaySize,
int
attachSize,
bool
canPostAttach,
int
maxAttachSize,
string
errMessage)
{
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;
}
private
string
m_attachExtensions;
///
<summary>
///
用户可以上传的文件类型
///
</summary>
public
string
AttachExtensions
{
get
{
return
m_attachExtensions; }
set
{ m_attachExtensions
=
value; }
}
private
string
m_attachExtensionsNoSize;
///
<summary>
///
用户可以上传的文件类型(不带上传数据大小)
///
</summary>
public
string
AttachExtensionsNoSize
{
get
{
return
m_attachExtensionsNoSize; }
set
{ m_attachExtensionsNoSize
=
value; }
}
private
int
m_maxTodaySize;
///
<summary>
///
得到今天允许用户上传的附件总大小(字节)
///
</summary>
public
int
MaxTodaySize
{
get
{
return
m_maxTodaySize; }
set
{ m_maxTodaySize
=
value; }
}
private
int
m_attachSize;
///
<summary>
///
今天可上传的大小
///
</summary>
public
int
AttachSize
{
get
{
return
m_attachSize; }
set
{ m_attachSize
=
value; }
}
private
bool
m_canPostAttach;
///
<summary>
///
是否允许上传附件
///
</summary>
public
bool
CanPostAttach
{
get
{
return
m_canPostAttach; }
set
{ m_canPostAttach
=
value; }
}
private
int
m_maxAttachSize;
///
<summary>
///
单个附件大小
///
</summary>
public
int
MaxAttachSize
{
get
{
return
m_maxAttachSize; }
set
{ m_maxAttachSize
=
value; }
}
private
string
m_errMessage;
///
<summary>
///
错误信息
///
</summary>
public
string
ErrMessage
{
get
{
return
m_errMessage; }
set
{ m_errMessage
=
value; }
}
private
int
m_maxAttachments;
///
<summary>
///
最大允许上传的附件数
///
</summary>
public
int
Maxattachments
{
get
{
return
m_maxAttachments; }
set
{ m_maxAttachments
=
value; }
}
}
#endregion
如果一切顺利,客户端会获取相应的UploadSetInfo实例信息来进行SL插件的信息绑定,也就是之前第
二张图中所说的信息内容(红框部分)。
如果当前用户通过验证,就可以通过SL上传附件了,因为用户上传的附件要进行实时统计,以即时更新
已上传附件的总和大小,来防止用户上传过量的附件),所以我在打开文件对话框事件中加入了到已上传
附件大小的统计以便进行控件:
///
<summary>
///
选择文件对话框事件
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
private
void
SelectFilesButton_Click(
object
sender, RoutedEventArgs e)
{
if
(AttachmentList.Count
>=
_maxAttachments)
{
ShowMessageBox(
"
\r\n您上传的文件数已达到系统规定的上限:
"
+
_maxAttachments
+
"
.
"
);
return
;
}
OpenFileDialog ofd
=
new
OpenFileDialog();
ofd.Multiselect
=
true
;
try
{
if
(
!
string
.IsNullOrEmpty(_fileFilter))
ofd.Filter
=
_fileFilter;
}
catch
(ArgumentException ex)
{
ShowMessageBox(
"
错误的文件过滤配置:
"
+
ex.Message);
}
if
(ofd.ShowDialog()
==
true
)
{
if
(filecount
==
0
)
filecount
=
AttachmentList.Count;
foreach
(FileInfo file
in
ofd.Files)
{
if
((filecount
+
1
)
>
_maxAttachments)
{
ShowMessageBox(
"
\r\n您上传的文件数已达到系统规定的上限:
"
+
_maxAttachments
+
"
.
"
);
return
;
}
filecount
++
;
string
fileName
=
file.Name;
UserFile userFile
=
new
UserFile();
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>
///
上传文件
///
</summary>
private
void
UploadAdvanced()
{
byte
[] buffer
=
new
byte
[
4
*
4096
];
int
bytesRead
=
_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>
///
上传附件
///
</summary>
///
<param name="fileName">
文件名称
</param>
///
<param name="data">
上传的字节数据
</param>
///
<param name="dataLength">
数据长度
</param>
///
<param name="parameters">
上传参数
</param>
///
<param name="firstChunk">
是否第一块数据
</param>
///
<param name="lastChunk">
是否最后一块数据
</param>
[WebMethod]
public
AttachmentInfo StoreFileAdvanced(
string
fileName,
byte
[] data,
int
dataLength,
string
parameters,
bool
firstChunk,
bool
lastChunk, CredentialInfo creinfo)
{
if
(AuthenticateUser(creinfo))
{
UploadSetInfo uploadSetInfo
=
GetAttachmentUploadSet(creinfo);
string
fileextname
=
Utils.CutString(fileName, fileName.LastIndexOf(
"
.
"
)
+
1
).ToLower();
if
(uploadSetInfo.CanPostAttach
&&
uploadSetInfo.AttachExtensionsNoSize.IndexOf(fileextname)
>=
0
&&
uploadSetInfo.AttachSize
>
dataLength
&&
Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))
{
string
uploadFolder
=
GetUploadFolder(fileName, creinfo.ForumID.ToString());
string
tempFileName
=
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);
}
FileStream fs
=
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);
return
Discuz.Forum.Attachments.GetAttachmentInfo(AddAttachment(fileName, creinfo));
}
}
}
return
null
;
}
上面代码会将客户端发送过来的分块数据进行组装到临时文件中,当该文件的所有分块数据传输完毕,
就会将该临时文件移动到指定的附件文件夹中,同时删除相应临时数据。大家注意到了,在该方法开始部分
还调用了AuthenticateUser方法(之前说明),这主要就是对安全性的考虑,必定HTTP是一种无状态协议呀。
上面的代码中这一行判断:
if
(uploadSetInfo.CanPostAttach
&&
uploadSetInfo.AttachExtensionsNoSize.IndexOf(fileextname)
>=
0
&&
uploadSetInfo.AttachSize
>
dataLength
&&
Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))
即是对当前用户上传信息(包括已上传附件大小,数量等)进行检验,以免出现上传数据超过系统限制
的情况。
在该方法的最后一行,会调用AddAttachment(fileName, creinfo)来进行相应附件信息的初始化绑定,
因为论坛中每个主题包括回帖都可以有附件,只不过对附件的扩展名和大小会有限制,所以这里通过该方法
进行封装,下面是其核心代码:
///
<summary>
///
添加附件
///
</summary>
///
<param name="fileName">
文件名称
</param>
///
<param name="creinfo">
认证信息
</param>
///
<returns>
返回当前插入的附件id
</returns>
private
int
AddAttachment(
string
fileName, CredentialInfo creinfo)
{
string
UploadDir
=
GetUploadFolder(fileName, creinfo.ForumID.ToString());
AttachmentInfo attachmentinfo
=
new
AttachmentInfo();
string
fileextname
=
Utils.CutString(fileName, fileName.LastIndexOf(
"
.
"
)
+
1
).ToLower();
string
newfilename
=
(Environment.TickCount
&
int
.MaxValue).ToString()
+
new
Random().Next(
1000
,
9999
)
+
"
.
"
+
fileextname;
try
{
//
如果是bmp jpg png图片类型
if
((fileextname
==
"
bmp
"
||
fileextname
==
"
jpg
"
||
fileextname
==
"
jpeg
"
||
fileextname
==
"
png
"
))
{
if
(Discuz.Common.Utils.FileExists(UploadDir
+
fileName))
{
System.Drawing.Image img
=
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
=
new
FileInfo(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
{
string
watermarkText;
watermarkText
=
config.Watermarktext.Replace(
"
{1}
"
, config.Forumtitle);
watermarkText
=
watermarkText.Replace(
"
{2}
"
,
"
http://
"
+
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
=
new
FileInfo(UploadDir
+
newfilename).Length;
}
}
}
else
{
System.IO.File.Move(UploadDir
+
fileName, UploadDir
+
newfilename);
attachmentinfo.Filesize
=
new
FileInfo(UploadDir
+
newfilename).Length;
}
}
catch
{}
if
(Discuz.Common.Utils.FileExists(UploadDir
+
fileName))
{
attachmentinfo.Filesize
=
new
FileInfo(UploadDir
+
fileName).Length;
attachmentinfo.Filename
=
GetDirInfo(fileName, creinfo.ForumID.ToString())
+
fileName;
}
if
(Discuz.Common.Utils.FileExists(UploadDir
+
newfilename))
{
attachmentinfo.Filesize
=
new
FileInfo(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
;
return
Discuz.Data.DatabaseProvider.GetInstance().CreateAttachment(attachmentinfo);
}
通过上面的方法就实现了将附件与相应的主题进行绑定功能同时为相应的图片附件加上水印。
到这里,主要的代码就介绍的差不多了。
当用户完成上传之后,点击“返回”按钮时,会触发下面事件:
///
<summary>
///
返回按钮事件
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
private
void
FinishUpload_Click(
object
sender, RoutedEventArgs e)
{
GetAttachmentList();
}
[ScriptableMember]
public
void
GetAttachmentList()
{
StringBuilder sb_attachments
=
new
StringBuilder();
sb_attachments.Append(
"
[
"
);
foreach
(AttachmentInfo attachmentInfo
in
AttachmentList)
{
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):
function
onLoad(plugin, userContext, sender) {
//
只读属性,标识 Silverlight 插件是否已经加载。
if
(sender.getHost().IsLoaded) {
$(
"
MultiUploadFile
"
).content.JavaScriptObject.UploadAttchmentList
=
getAttachmentList;
}
}
//
获取silverlight插件已经上传的附件列表
function
getAttachmentList(sender, args) {
var
attachment
=
args.AttchmentList;
if
(isUndefined(attachment)
||
attachment
==
'
[]
'
) {
BOX_remove(
'
silverlightControlHost
'
);
return
;
}
var
attachmentList
=
eval(
"
(
"
+
attachment
+
"
)
"
);
BOX_remove(
'
silverlightControlHost
'
);
addAttachUploaded(attachmentList);
}
这样一个SL多文件上传插件就算基本完成了。当然我还写了“缩略图”功能,因为代码很简单就不
多说了。
好了,今天的内容就先到这里了。
原文链接: http://www.cnblogs.com/daizhj/archive/2009/04/07/1431090.html
作者: daizhj, 代震军
Tags: silverlight,discuznt,uploadfile,文件上传
网址: http://daizhj.cnblogs.com/