在去年我曾写过一篇文章:“
推荐一个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 %>
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>
/// <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>
/// <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来完成的:
{
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中的几个上传按钮“置灰”,以免未登陆的用户上传附件。
如果用户的Cookie有效(已登陆过),则直接获取该用户所在用户组及其它相关联的权限信息, 如果无效,则提示用户登陆,同时将SL中的几个上传按钮“置灰”,以免未登陆的用户上传附件。
下面就是其向服务器请求谁信息的代码:
_client.GetAttachmentUploadSetCompleted += new EventHandler < GetAttachmentUploadSetCompletedEventArgs >
(_client_GetAttachmentUploadSetCompleted);
_client.GetAttachmentUploadSetAsync(_creInfo, _forumid);
上面客户端请求下面的服务端代码:
/// 通过指定用户认证信息来获得该用户的上传设置信息
/// </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>
/// WEB权限认证
/// <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类实例,其包括:
2.用户可以上传的文件类型(不带上传数据大小)
3.得到今天允许用户上传的附件总大小(字节)
4.是否允许上传附件
5.单个附件大小
6.最大允许上传的附件数
7.错误信息
/// <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插件的信息绑定,也就是之前第二张图中所说的信息内容(红框部分)。
本文转自 daizhenjun 51CTO博客,原文链接:http://blog.51cto.com/daizhj/147172,如需转载请自行联系原作者