宝玉的blog

专注于web开发技术
随笔 - 81, 评论 - 1563, 引用 - 157

导航

关于


目前致力于ChinaCommunityServer的开发。

msn: junminliu(at)msn.com

标签

每月存档

最新留言

  • re:发布一个爱心小软件——网页抓图
    <p>你好 我看了你的代码 不错啊,请问在asp.net C#中 没有了webbrowser 该怎么实现?</p> <p><a href="http...
    by weblogical(注册) on 2009/9/9 17:22:55
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:37
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:31
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:30
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:29
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:25
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:25
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:25
  • re:Openlab V2.0 Beta
    <p>宝玉你好: &nbsp; &nbsp; &nbsp; 我是个.net新手,最近看了openlab(openlab_V2.0_Beta)的源码。 ...
    by isforge(注册) on 2009/6/28 10:10:25
  • re:Silverlight中,防止ComboBox抢焦点
    <p>我是初学者,您已经写了一个 组件上传的功能 。。我在2008下测试通过,,,但是弄2005测试的时候 发现 progress.aspx.cs页面的</p> <p&...
    by jxh12345j(注册) on 2009/4/7 8:55:12
  • ufnnutdh - Google Search
    ufnnutdh - Google Search
    by (匿名) on 2008/10/27 17:44:45
  • veysaync - Google Search
    veysaync - Google Search
    by (匿名) on 2008/10/5 5:20:49
  • mzgmhgio - Google Search
    mzgmhgio - Google Search
    by (匿名) on 2008/9/22 23:34:49
  • rhmhnyma - Google Search
    rhmhnyma - Google Search
    by (匿名) on 2008/9/22 7:48:44
  • re: 发布一个爱心小软件——网页抓图
    Maxthon应该有这个功能
    by passos(匿名) on 2008/7/21 20:05:23

广告

CnForums2.x体验

基于CommunityServer本地化开发,除论坛外,还有blog和相册系统,更有丰富的插件功能。

下载: http://www.CommunityServer.cn/builds

posted on 2005-06-17 05:26:00 by 宝玉  评论(20) 阅读(7557)

CnForums和已有系统的整合方案

可能我们已经有了一个完整的系统,已经有了一套用户系统,而需要加上论坛,也就是和CnForums整合,希望能共享验证,共享用户资料。可能有很多种方案,以我以前写过的一套解决方案为例,说明一下思路和具体实现过程,抛砖引玉:

先说说用户共享,最理想的做法是共享一个用户库,而一般都不太方便,所以最简单有效的方法就是保证两个用户库的同步,也就是以前系统的用户表数据在CnForums的表数据有一份拷贝,所有系统的注册/修改资料/登录在同一个入口,修改资料则同步修改,注册用户则同步插入。要注意CnForums中数据表有2个:forums_Users、forums_UserProfile ,以UserID关联,在同步用户数据的时候,最好直接使用CnForums现有的注册/修改资料的存储过程forums_User_CreateUpdateDelete,或者参考其实现。(特别注意一下,如果你想密码也同步,就要注意@PasswordFormat参数,如果以前系统的密码没有加密,那么该参数的值就设置为0,否则就设置一个10以后的数字)
具体实现就是将CnForums的所有表和存储过程安装在原来的数据库上,因为CnForums的所有存储过程和表都是forums_开头,所以很容易区分。用SQL调用CnForums的forums_User_CreateUpdateDelete存储过程或参考其实现,写个SQL或者导入程序把以前系统的用户数据导入到CnForums的用户表中,修改 修改资料和注册的程序,保证两个地方用户数据的同步。

用户同步后,就是共享登录验证,共享登录验证有两种方案,一种就是保证密码同步、另一种就是只采用一个系统的登录验证。
先说说第一种,CnForums可以支持多种密码验证方案,如果你以前密码没有加密,那么什么都不用改,只要注意在同步用户的时候用户资料的PasswordFormat字段为0。如果是自己的加密方式,那么就要修改一下CnForums的相关源码,在AspNetForums.Enumerations.UserPasswordFormat中增加枚举,枚举的数值和同步用户数据时@PasswordFormat参数参数的值一致,这就是为什么让你设置一个10以上的数字了。再在AspNetForums.Users.public static string Encrypt(UserPasswordFormat format, string cleanString, string salt)方法中增加您原来系统的加密算法。
如果您嫌第一种复杂,那么就可以采用第二种,共用一个登录验证,CnForums使用的是asp.net的Forms验证,在登录成功授权的时候,记录登录的用户名(username)(祥见AspNetForums.Controls中的Login.cs:FormsAuthentication.SetAuthCookie(userToLogin.Username, autoLogin.Checked)Wink,以后每次获取用户资料都是根据这个登录用户名来取用户资料(具体参考AspNetForums.Users.GetUser()、AspNetForums.Users.GetLoggedOnUsername()和AspNetForums.ForumsHttpModule.Application_AuthenticateRequest(Object source, EventArgs e)方法,ForumContext.Current.UserName = context.User.Identity.Name;),所以我们如果要让CnForums共享主系统的登录验证,可以在主系统登录成功后,也记录当前登录的Username,也就是Login.cs中的FormsAuthentication.SetAuthCookie(userToLogin.Username, autoLogin.Checked),在CnForums中,只要表中有当前登录的这个用户,就会认为当前这个用户是登录过的(在CnForums的HttpModule里面,如果当前登录的Username在表中没记录,则会自动注销,所以一定要保持用户表的同步)。还有要注意就是Forms验证不能跨域,所以就要让CnForums免虚拟目录安装,具体方法可搜索以前的帖子。
第二种方案的具体实现:
免虚拟目录安装好CnForums;
在主系统的登录程序中,密码校验成功后,使用FormsAuthentication.SetAuthCookie(username, autoLogin)方法设置登录成功,这样,当主系统登录后,CnForums就也是成功登录的。

posted on 2005-05-31 00:05:00 by 宝玉  评论(17) 阅读(6691)

AspNetForums中基于角色的权限控制

AspNetForums中对于用户权限,是类似于Windows系统采用基于角色(Role)的权限控制,这样,我们就可以根据需要,设定不同的角色,设置各个角色的权限,并将各个用户属于不同的角色。根据用户所属的角色,来判断用户可以有哪些权限,进行哪些操作。

先看看数据库设计
forums_Users表,用户表,UserID为主键,唯一确定一个用户
forums_Roles表,角色表,RoleID为主键,唯一确定一个角色
forums_UsersInRoles表,用户和角色对应关系表,存储用户所在的角色
forums_ForumPermissions表,角色在某版块的权限,记录了在每个版块中各个角色可以有权限进行哪些操作

再看看是如何来判断用户操作权限的:
当用户登录后,要获取论坛所有版块的信息并缓存,在获取版块信息的同时,要获取当前用户在每个版块操作(如发表新帖、投票、附件等)的权限。操作权限有三种:"有权限"、"无权限"和"未设置",如果是未设置,那么就看这个操作的默认权限是什么。一个用户可以属于多个角色,每个角色对应的操作权限不一样,要判断这个用户有没有当前操作的权限,则遍历这个用户所属的所有角色,如果任一角色有权限,那么该用户就有该操作的权限。具体实现请参考源码:
Components\Forums.cs中的GetForums(ForumContext forumContext, int userID, bool ignorePermissions, bool cacheable)方法和Components\Provider\ForumsDataProvider.cs中PopulateForumPermissionRightFromIDataReader方法。

角色和web.config的结合
Asp.Net有一个功能就是可以用于控制对 URL 资源的客户端访问(可参考QuickStart上的说明)。它对于用于生成请求的 HTTP 方法(GETPOST)是可配置的,并且可被配置为允许或拒绝访问用户组或角色组。这个方法也被应用到AspNetForums中,例如在admin目录(管理员操作相关页面)和Moderate目录(版主操作相关页面)下都有一个web.config目录,通过web.config,可以设定其所在目录的URL客户端访问权限。

以Admin目录下的web.config中的配置为例:
 <authorization>
  <allow roles="Global Administrators" />
  <allow roles="Site Administrators" />
  <deny users="*" />
 </authorization>
这个表示对于属于Global Administrators角色和Site Administrators角色授权,其他任何用户都禁止访问该目录下的页面。因为对于部分页面,希望版主也可以进行访问,那么可以增加如下配置:
    <location path="ForumAdmin.aspx">
      <system.web>
        <authorization>
          <allow roles="Global Administrators" />
          <allow roles="Site Administrators" />
          <allow roles="Global Moderators" />
          <allow roles="Site Moderators" />
          <deny users="?" />
        </authorization>
      </system.web>
    </location>   
这样,对于/Admin/ForumAdmin.aspx这个URL,属于Global Moderators或Site Moderators角色的用户也可以有权访问。

怎么设置登录用户的角色
具体实现请参考源码:Components\Roles.cs 和文章《如何使用 Forms 身份验证创建 GenericPrincipal 对象

附:CnForums源码下载

posted on 2005-02-24 00:31:00 by 宝玉  评论(31) 阅读(22087)

Asp.Net Forums中的自定义异常类

Forums中有一个自定义的异常类ForumException,继承自ApplicationException,与之对应的有一个枚举ForumExceptionType,用来记录异常的类型。Forums的自定义异常类主要是对可能出现的各种异常分别进行处理——记录错误日志消息提示

当asp.net中抛出异常后,会触发HttpApplication的Error事件,可以在HttpModule中捕获到,如Forums就是在其HttpModule中处理Forums的异常:application.Error += new EventHandler(this.Application_OnError);。在捕获到自定义异常后,根据异常的类别(ForumExceptionType枚举)对一些重要的错误信息记录日志(保存到数据库的forums_Exceptions表),以供管理员参考。而对于异常,为了给用户友好的提示,会将根据异常类显示出比较友好的错误信息。

Forums的自定义异常不仅仅作用在于对错误异常的处理,而且还有一个重要作用就是用来做信息提示用,例如提示用户注册成功,那么抛出一个异常:throw new ForumException(ForumExceptionType.UserAccountCreatedAuto); 然后就会自动跳转到大家所看到的提示用户已经成功注册的信息。

Forums是怎么样根据异常跳转到对应的信息呢?前面说了Forums对于每个自定异常都对应有一个错误类型枚举ForumExceptionType,Forums针对每一种语言都有一个Messages.xml,xml的规则如下:

<root> <message id="1"> <title>无权限登录</title> <body>您不是超级管理员.</body> </message> <message id="2"> <title>无权限修改</title> <body>此版块不存在,或您无权限修改.</body> </message> </root>

其中的id和ForumExceptionType的int型一一对应

public enum ForumExceptionType { AdministrationAccessDenied = 1, PostEditAccessDenied = 2, }

那么在HttpModule中处理异常时,直接跳转到消息提示页Response.Redirect(Globals.GetSiteUrls().Message( exception.ExceptionType ), true);,如http://localhost/CnForums/Msgs/default.aspx?MessageID=1 在msg的显示页,会根据MessageID,从xml中找到对应的提示信息,显示在页面上。

posted on 2005-01-20 20:29:00 by 宝玉  评论(24) 阅读(9564)

Asp.Net Forums之邮件发送

Forums中很多地方要用到邮件发送,如:邮件注册、找回密码、邮件订阅等。

添加新贴的代码流程非常慢。每次添加帖子,应用程序首先要确保没有重复贴,然后格式化帖子内容和表情图像,记号并索引,如果必要还要将帖子添加到相应的队列中,对附件进行有效性检查,最终完成发贴后,给预订者发出 e-mail 通知。显然,这里做的工作太多。索引帖子是一个很耗时的操作,此外,内建的 System.Web.Mail 功能要与 SMTP 服务器连接并顺序发送邮件。当特定帖子或主题预定者数量增加时,发送帖子的执行时间会越来越长。

  并不是每个请求都需要索引邮件,所以Forums采用的是批量集中处理,并且一次只索引25个帖子或每隔五分钟发送一次邮件。定时器这部分在我的上一个blog有说明《asp.net forums中定时器的应用

在Asp.Net中邮件发送非常容易,一般都需要Smtp服务器,但是一些免费信箱的Smtp服务器(如smtp.163.com)都需要账号密码验证。在MailMessage对象的Filds集合中加入以下内容即可:

Message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1" );
//basic authentication
Message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", txtUserName.Text );
// 设置smtp服务器登录账号(如您163.com的信箱账号)
Message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", txtPassword.Text );
// 设置smtp服务器登录密码 (如您的163.com的信箱账号密码)

但是使用免费的Smtp服务器一定要注意一个问题,就是发送邮件的账号(即Message.From)必须和上面的Smtp服务器登录账号一致,否则将会导致找不到cdo对象的异常。

示例代码:
邮件发送示例代码

posted on 2005-01-15 20:32:00 by 宝玉  评论(29) 阅读(13645)

asp.net forums中定时器的应用

在Asp.Net中使用定时器,破宝之前已有Blog写过《在 ASP.NET 中使用计时器(Timer)》,这里主要针对Asp.Net Forums来说一下其具体实现。

在Asp.Net Forums中,对定时器有如下应用:
1. 更新论坛统计信息
2. 定时索引指定条数的帖子
3. 定时群发队列中的邮件

Forums中对定时器的调用是放在自定义HttpModule的Init方法中(如果您没有使用HttpModule,也可以在Globals.aspx中的Application_OnStart 中调用定时器)。

        // 定时器
        static Timer statsTimer;
        
static Timer emailTimer;

        
// 定时间隔
        private long EmailInterval = ForumConfiguration.GetConfig().ThreadIntervalEmail * 60000;
        
private long StatsInterval = ForumConfiguration.GetConfig().ThreadIntervalStats * 60000;

        
public String ModuleName 
            
get return "ForumsHttpModule"; } 
        }
    


        
// *********************************************************************
        
//  ForumsHttpModule
        
//
        /// <summary>
        
/// Initializes the HttpModule and performs the wireup of all application
        
/// events.
        
/// </summary>
        
/// <param name="application">Application the module is being run for</param>

        public void Init(HttpApplication application) 

            
// Wire-up application events
            
//
            
// 略去其他代码
            
            ForumConfiguration forumConfig 
= ForumConfiguration.GetConfig();

            
// 如果使用定时器并且定时器还没初始化
            if( forumConfig != null
            
&&  forumConfig.IsBackgroundThreadingDisabled == false ) {
                
if (emailTimer == null)
                    
// 新建定时器
                    
// 新建一个TimerCallback委托,具体要执行的方法在ScheduledWorkCallbackEmailInterval中
                    emailTimer = new Timer(new TimerCallback(ScheduledWorkCallbackEmailInterval), application.Context, EmailInterval, EmailInterval);

                
if( forumConfig.IsIndexingDisabled == false 
                
&&    statsTimer == null ) {
                    statsTimer 
= new Timer(new TimerCallback(ScheduledWorkCallbackStatsInterval), application.Context, StatsInterval, StatsInterval);
            }

        }

        }


        
/// <summary>
        
/// 释放定时器
        
/// </summary>

        public void Dispose() {
            statsTimer 
= null;
            emailTimer 
= null;
        }


        
Timer Callbacks

其实稍加改进就可以应用到我们自己的项目中,例如前不久刚做一个项目,因为数据量过于庞大,每次从数据库取非常慢,然后改成使用定时器,每隔12小时将最新的数据列表生成静态的文本。

BTW: 有技术八股文之嫌哦:P

posted on 2004-12-20 14:04:00 by 宝玉  评论(15) 阅读(17023)

Asp.Net Forums中对.Net中序列化和反序列化的应用

在Forums中,有些内容是不固定的,例如用户资料,除了一些基本资料,可能还要有一些其他资料信息,例如MSN、个人主页、签名档等,一般对于这样的都是每一个属性对应于数据库中的一个字段。但是如果以后我们因为需要增加一些属性,例如QQ号、Blog地址等,如果还是用这种增加数据表字段的方法,那么将会频繁的修改数据库表结构、存储过程、数据库访问的程序。

或许您也遇到过类似问题,看Forums中是怎么借用.Net的序列化和反序列化来解决的:
例如我需要在用户资料里面增加QQ号这个属性,那么我只需要在User类中增加一个属性
public String QQIM 
{
    get { return GetExtendedAttribute("QQIM"); }
    set { SetExtendedAttribute("QQIM", value); }
}
不需要修改数据库表结构,不需要修改存储过程,连数据库访问的程序都不需要动。

其具体实现的主要代码:

// 首先新建在User类中新建一个NameValueCollection对象,将这些扩展属性都保存在NameValueCollection对象中
NameValueCollection extendedAttributes = new NameValueCollection();

// 从NameValueCollection集合中取纪录
public string GetExtendedAttribute(string name)    
{
    
string returnValue = extendedAttributes[name];

    
if (returnValue    == null)
    
return string.Empty;
    
else
    
return returnValue;
}


// 设置扩展属性的在NameValueCollection中的键值和值
public void SetExtendedAttribute(string    name, string value)    
{
    extendedAttributes[name] 
= value;
}


// 将extendedAttributes对象(前面定义的用来保存所有的用户扩展信息的NameValueCollection对象)序列化为内存流
// 可以用来保存到数据库中
public byte[] SerializeExtendedAttributes()    
{

    
// 序列化对象
    BinaryFormatter    binaryFormatter    = new BinaryFormatter();

    
// 创建一个内存流,序列化后保存在其中
    MemoryStream ms    = new MemoryStream();
    
byte[] b;

    
// 将extendedAttributes对象(里面保存了所有的用户扩展信息)序列化为内存流
    
//
    binaryFormatter.Serialize(ms, extendedAttributes);

    
// 设置内存流的起始位置
    
//
    ms.Position    = 0;
        
    
// 读入到 byte 数组
    
//
    b =    new    Byte[ms.Length];
    ms.Read(b, 
0, b.Length);
    ms.Close();

    
return b;
}


// 反序列化extendedAttributes对象的内容
// 从数据库中读取出来的
public void DeserializeExtendedAttributes(byte[] serializedExtendedAttributes) 
{

    
if (serializedExtendedAttributes.Length    == 0)
    
return;
    
try    
    
{

    BinaryFormatter    binaryFormatter    
= new BinaryFormatter();
    MemoryStream ms    
= new MemoryStream();

    
// 将 byte 数组到内存流
    
//
    ms.Write(serializedExtendedAttributes, 0, serializedExtendedAttributes.Length);

    
// 将内存流的位置到最开始位置
    
//
    ms.Position    = 0;

    
// 反序列化成NameValueCollection对象,创建出与原对象完全相同的副本
    
//
    extendedAttributes = (NameValueCollection) binaryFormatter.Deserialize(ms);

    ms.Close();
    }
 
    
catch    {}
    
}

实质上序列化机制是将类的值转化为一个一般的(即连续的)字节流,然后就可以将该流保存到数据库的某个字段中(在数据库中forums_UserProfile表中有一个字段“StringNameValues varbinary(7500)”)。读取的过程对对象进行反序列化时,创建出与原对象完全相同的副本。

注意一般这类属性在数据库中是不能被检索到的,并且要这些属性能被序列化。

更详细内容请查阅MSDN和Asp.Net Forums源码

posted on 2004-12-10 13:44:00 by 宝玉  评论(41) 阅读(18083)

Powered by: Joycode.MVC引擎 0.5.2.0