none
DiscuzNT使用Silverlight进行多文件上传 RRS feed

  • 常规讨论

  • 这个项目为原型,简要介绍一下在
    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(
    010)).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<stringstring> 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(""""00false0"当前用户信息无效,请尝试刷新");

            UserGroupInfo usergroupinfo 
    = Discuz.Forum.UserGroups.GetUserGroupInfo(userinfo.Groupid);
            
    if (usergroupinfo == null)
                
    return new UploadSetInfo(""""00false0"当前用户所属用户组信息无效");


            ForumInfo forum 
    = Discuz.Forum.Forums.GetForumInfo(creinfo.ForumID);
            
    if (forum == null)
                
    return new UploadSetInfo(nullnull00false0"当前版块信息无效,请尝试刷新");

            
    //得到用户可以上传的文件类型
            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(""""00false0"当前用户信息无效,请尝试刷新");
    }

     

         该方法的首先会访问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(
    010)).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>
    2009年5月27日 5:27