导航

聚合

«2010年3月»
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Blog统计

新闻/公告

最近评论

存档

随笔分类

文章分类

相册

2007年6月14日

Google 博客搜索 Ping 服务应用

Google Ping 介绍

通 过 Google“博客搜索”Ping API, 用户可以程序化的方式将博客内容的更新通知给 Google“博客搜索”引擎。这对于经常更新博客内容的用户尤其有用。博客服务提供商的管理人员也可以利用此API将其平台上的博客内容变化向 Google 通告,以便 Google“博客搜索”及时抓取来自这一服务提供商的最新内容。为设置对 Google“博客搜索”的自动 Ping 机制,请按照如下所述设置XML-RPC客户端或REST客户端以发送请求。您可以任选一种方法进行通知;两者都将按照相同的方式进行处理。


 设置XML-RPC客户

XML-RPC客户的请求应包含如下元素:

RPC端点: http://blogsearch.google.com/ping/RPC2
调用方法名: weblogUpdates.extendedPing
参数: (应按照如下所列的相同顺序传送)

  • 站点名
  • 站点URL
  • 需要检查更新的页面URL
  • 相应的RSS、RDF或Atom种子的URL
  • 可选 页面内容的分类名称(或标签)。您可以指定多个值,之间用'|'字符进行分隔。

XML-RPC响应中将返回含有两个元素的<struct> :

  • flerror (Boolean):当有错误发生时设为true/1
  • message (string) :"Thanks for the ping." (如果成功) 或者一个错误信息(如果不成功)。

XML-RPC请求的例子


POST /RPC2 HTTP/1.0
User-Agent: request
Host: blogsearch.google.com
Content-Type: text/xml
Content-length: 447

<?xml version="1.0"?>
<methodCall>
<methodName>weblogUpdates.extendedPing</methodName>
<params>
<param>
<value>Official Google Blog</value>
</param>
<param>
<value>http://googleblog.blogspot.com/</value>
</param>
<param>
<value>http://googleblog.blogspot.com/</value>
</param>
<param>
<value>http://googleblog.blogspot.com/atom.xml</value>
</param>
</params>
</methodCall>

XML-RPC响应的例子


HTTP/1.1 200 OK
Connection: close
Content-Length: 451
Content-Type: text/xml
Date: Sun, 30 Sep 2001 20:02:30 GMT
Server: Apache

<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>flerror</name>
<value>
<boolean>0</boolean>
</value>
</member>
<member>
<name>message</name>
<value>Thanks for the ping.</value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>

  设置REST客户

REST客户的请求中包含如下元素:

URL: http://blogsearch.google.com/ping

参数:

  • name = 博客的名字
  • url = 博客的URL
  • changesURL = RSS、RDF或Atom种子的URL (可选)
响应中将返回文本内容,在成功的时候是"Thanks for the ping.",在失败时是一条错误消息。

例子:



  changes.xml的格式

Google 将所接受的“博客搜索” Ping 记录以XML格式发布到http://blogsearch.google.com/changes.xml。changes.xml文件格式包含一个根元素<weblogUpdates>和一个或多个的<weblog>元素。

<weblogUpdates version="2" updated="Wed, 30 May 2006 14:10:00 GMT" count="1384779">
<weblog name="Some Blog"
url="http://googleblog.blogspot.com"
rssUrl="http://googleblog.blogspot.com/atom.xml"
when="1"/>
...
</weblogUpdates>

<weblogUpdates>元素

  • version:用来指示一个主要的格式变化,目前的版本是2。
  • updated:以 HTTP 1.0格式表示的日期时间。它指示了该文件上一次更新的时间。
  • count:一个递增的数字,表示了changes.xml文件的版本。新版本changes.xml文件通常具有更大的count值。

<weblog>元素

  • name:Blog的名称。
  • url: Blog的url。
  • rssUrl: 相应的RSS、Atom或其它种子的URL。
  • when: <weblogUpdates>元素的updated属性对应的时间减去相应的 Ping 发生的时间的差值,单位为秒。
====================================================================

下面实现如何使用XML RPC编程实现Google Ping服务.

首先,下载CookComputing.XmlRpc

我使用的是2.0版本.最新版为2.1.0

1.建立xml rpc客户端

 public class GoogleXmlRpc
    {
        /// <summary>
        /// 返回值,用于处理Google Ping返回值的结构
        /// </summary>
        public struct ReturnValue
        {
            public bool flerror;
            public string message;
        }

        [XmlRpcUrl("http://blogsearch.google.com/ping/RPC2")]
        public interface IGooglePing : IXmlRpcProxy
        {
            [XmlRpcMethod("weblogUpdates.extendedPing")]
            ReturnValue Ping(string websiteName, string websiteUrl, string changedUrl, string feedUrl);
        }
       
    }


2.向Google发出一个ping通告

在你的程序添加文章或更新文章时,发出ping通告.

        string websiteName="venjiang 的博客";                                                 // 博客名称
        string websiteUrl="http://blog.hidotnet.com/venjiang/";      // 博客网站地址
        string changeUrl = "http://blog.hidotnet.com/venjiang/";                      // 要更新的地址
        string feedUrl = "http://blog.hidotnet.com/venjiang/Rss.aspx";          // 聚合地址rss或atom

        GoogleXmlRpc.IGooglePing proxy = (GoogleXmlRpc.IGooglePing)XmlRpcProxyGen.Create(typeof(GoogleXmlRpc.IGooglePing));   // 创建代理类

       // 最新版本,支持泛型,可以直接使用:

       // GoogleXmlRpc.IGooglePing proxy =XmlRpcProxyGen.Create<GoogleXmlRpc.IGooglePing>();

        GoogleXmlRpc.ReturnValue returnValue = proxy.Ping(websiteName, websiteUrl, changeUrl, feedUrl);   // ping

        if (returnValue.flerror)
            Response.Write( "Google Ping 出错!");
        else
            Response.Write "Google Ping 成功!";


3.查看google 更新列表

下载:http://blogsearch.google.com/changes.xml 你可以看到你的博客相关信息已加入更新列表,目前google更新列表,有一定延迟.

发表于 @ 2007年6月14日 17:02 | 评论 (1757)

2007年3月10日

测试使用新的缓存机制

测试使用新的缓存机制,前台是否即时更新.
临时解决访问速度慢问题.
前台不能即时呈现时请点击右侧刷新按钮,
如果发现更多问题,请即时联系我.

发表于 @ 2007年3月10日 1:04 | 评论 (590)

2006年12月18日

安装Visual Studio 2005 Service Pack 1

前几日jacky告诉我vs2k5 sp1出了,随即下载.今日抽空赶紧安装.

准备环境:

Microsoft? Visual Studio? 2005 Service Pack 1

下面为中文版
下载地址:
Microsoft? Visual Studio? 2005 Service Pack 1
下载地址:
http://www.microsoft.com/downloads/details.aspx?FamilyID=bb4a75ab-e2d4-4c96-b39d-37baf6b5b1dc&DisplayLang=zh-cn

  • 安装要求:
    • 目标计算机上必须安装了受支持的 Visual Studio® 2005 产品副本。
    • 目标计算机上安装了 Microsoft® Windows® Installer 3.1 或更高版本。
    • 至少 192MB 的 RAM。建议使用 256MB 或更大内存。
    • 硬盘空间至少为 6.2GB
      • 如果目标计算机上安装了多个 Visual Studio® 2005 产品,硬盘空间要求也会相应大大增加。


  • 安装可能出现问题解决办法:
    http://support.microsoft.com/kb/925336 

    几个朋友提示安装过程费了些周折,为避免安装出现问题,请按上面的方法,先修改本地安全策略.
    M$这个要求有6G空间,这个实在有些愁人,一些朋友也因空间问题安装出错,抓紧整理我的硬盘空间,但资料实在太多,一时半日无法整理出6G空间.一个补丁400M,干嘛要求这么多空间,M$不是在折腾我们嘛. 决定尝试安装.

    安装前环境:
    剩余空间:
    C: 3.88G
    D: 3.57G

    Visual Studio 2005 安装在D盘,临时文件夹在C盘,如果你有修改系统临时文件夹路径,确保所在盘有足够空间.
    Visual Studio 2005我是重新安装的,没有安装VB,VC++,其余都有安装.上面所列硬盘空间容量为安装VS2005后剩余.

    安装过程中:
    剩余空间:
    C: 2.54G
    临时文件写入,然后开始收集信息,过程比较漫长.这个时间你可以去看电视了.或者干脆小睡一会儿,不知道M$花这么长时间收集什么,小心把电脑里的MM搜集走. 在这个过程中,临时文件夹写入450多M,C盘其它地方写入不到1G, 任务管理器查看,整个SP1补丁被全部载入内存,安装程序占用CPU 50%左右.为避免出现什么异外,建议不要开太多程序.


    搜集完信息,开始安装....

    这个时间不准确,可以去抽颗烟,喝杯咖啡.

    安装完成后:
    剩余空间:
    C: 2.98G
    D: 3.56G


    VS2005版本


    总结:
    整个过程安装比较顺利,可以看到在搜集信息时,C盘写入1.34G,安装完成后,删除了临时文件,减少450M,D盘,也就是VS2005所在文件夹写入信息并不多.这样看来,如果只安装C#版本的VS,打补丁,C盘有1.5G应该足够了,VS2005安装所在目录并不需要太多空间.当然,如果你的VS2005安装的组件比较多的话,相应空间要求会提高不少.但至少6G这个要求并不是必须的.

    测试:
    终于可以在中文版上运行Web Application Project了.
    新建:


    项目解决方案:


    编译:


    运行:


    另.打开先前M$提供的Web Application Project 项目,可以成功加载.

    至此,Visual Studio? 2005 Service Pack 1安装完毕.

    发表于 @ 2006年12月18日 3:02 | 评论 (848)

    2006年12月13日

    测试

    BSP防范Trackback垃圾的一种方法

    发布Asp.Net Forums V2.2.1929 官方中文Beta版



    测试trackback

    发表于 @ 2006年12月13日 2:40 | 评论 (1538)

    2006年10月25日

    BlogML 2.0 is Released

    BlogML是什么?
    BlogML是blog内容的XML格式存储,你能够使用它归档blog内容,或者作为博客转换/迁移的标准格式.当前已有数个blog引擎提供了这个支持.
    • Community Server
    • Das Blog
    • Subtext
    • SingleUserBlog


    你能够在这里下载 BlogML 2.0.

    发表于 @ 2006年10月25日 11:15 | 评论 (8664)

    2006年10月13日

    SqlServer数据访问帮助类 for .Net 2.0

    =================================================================
    // SqlServer数据访问帮助类
    =================================================================
    // 名字空间: hiDotNet.Data
    // 描    述: SqlServer数据访问帮助类.
    // 日    期: 2006年3月14日
    // 修订日期: 2006年3月17日
    // 联    系: venjiang@msn.com
    // 说    明: 实现SqlServer的快速访问
    =================================================================
    // 版权所有,hiDotNet.com 更多内容请访问: www.hiDotNet.com
    =================================================================

    [示例运行环境]
    .Net Framework 2.0
    Sql Server 2000

    [步骤]
    1.执行SetupDataBase.bat,安装示例数据库所需内容.
    2.使用Vs2005打开SqlHelperTest.csproj,编译运行.

    欢迎测试反馈.
    示例截图:

    帮助

     

    点击下载

    发表于 @ 2006年10月13日 23:06 | 评论 (577)

    以增加收藏夹功能为实例,解析asp.net forums2结构流程及组件设计

    其实asp.net forums2就是像搭积木,现以收藏夹功能实例看一下asp.net forums的结构及组件设计,希望给朋友以参考。

    示例:帖子收藏功能(by venjiang 20040912) √

    一.增加资源文件项目
    修改Web\Languages\zh
    -CN\Resources.xml,增加
    <!-- 收藏夹 -->
    <resource name = "MyFavorite_Title">收藏夹</resource>
    <resource name = "MyFavorite_Description">我收藏的主题</resource>
    <!-- 收藏夹-结束 -->

    二.增加站点url
    修改E:\WWW\cnforums0804\Web\SiteUrls.config,增加
    <url name="user_MyFavorite" path="/User/MyFavorite.aspx" />

    三.增加属性
    修改Components\Components\SiteUrls.cs,增加
    // 收藏夹 by venjiang 0911
            public string MyFavorite
            {
               
    get { return paths["MyFavorite"]; }
            }

    四.修改相应的界面文件
    修改Web\Themes\
    default\Skins\View-MyForums.ascx,
    修改Web\Themes\
    default\Skins\View-PrivateMessages.ascx
    修改Web\Themes\
    default\Skins\Skin-EditProfile.ascx

    在UserPrivateMessages后增加
      
    <td width="15">&nbsp;</td>
             
    <td id="1" class="ControlPanelTabInactive" align="center" nowrap>
               
    <a href="<%=Globals.GetSiteUrls().MyFavorites%>"><%=ResourceManager.GetString("MyFavorites_Title")%></a>
             
    </td>
    修改: 
    <td colspan=11 class="ControlPanelTabLine"><img width="1" height=1 alt=""></td>跨跃列数

    五.增加相应文件

    表现层1,收藏夹主视图
    在web
    /user/目录增加MyFavorites.aspx,最终用户页面
    在Controls\Views目录增加MyFavoritesView.cs,页面视图服务器控件(主要表现为页面处理逻辑)
    界面视图:在Web\Themes\
    default\Skins中增加View-MyFavorites.ascx 收藏夹视图(主要表现为页面UI)

    组件
    在Components目录增加Favorites.cs(相当于业务逻辑层,加s表业务处理),此例中未在子目录Components
    /Components中增加Favorite.cs(相当于业务实体层,未加s表实体),因并不需要,完整的Asp.net forums模式应该还有这一层。

    表现层2,用户点击收藏按钮后呈现的UI
    (这个比较简单)
    在web目录增加MyFavoritesAdd.aspx文件
    处理加入收藏时服务器控件, 在Controls目录增加MyFavoritesAdd.cs(页面处理逻辑)
    在Web\Themes\
    default\Skins中增加Skin-MyFavoritesAdd.ascx将主题加入收藏时的视图(UI)

    六.数据库
    增加表forums_Favorites
    UserID   
    int    4    0
    ThreadID   
    int    4    0
    FavoriteDate    datetime   
    8    0

    创建存储过程forums_Favorites_CreateDelete
    CREATE  procedure forums_Favorites_CreateDelete
    (
        @UserID
    int,
        @ThreadID
    int,
        @Action
    int
    )
    AS
    BEGIN

    IF @Action
    = 0
    BEGIN
       
    -- Does the user already have the ability to see this thread?
        IF EXISTS (SELECT UserID FROM forums_Favorites WHERE UserID
    = @UserID and ThreadID = @ThreadID)
           
    return

        INSERT INTO
            forums_Favorites
        VALUES
            (
                @UserID,
                @ThreadID,
                getdate()
            )

        RETURN
    END

    IF @Action
    = 2
    BEGIN
        DELETE
            forums_Favorites
        WHERE
            UserID
    = @UserID AND
            ThreadID
    = @ThreadID
        RETURN
    END

    END
    GO
    SET QUOTED_IDENTIFIER OFF
    GO
    SET ANSI_NULLS ON
    GO

    七.数据处理
    1.Components\Provider\ForumsDataProvider.cs增加
    #region 收藏夹
           
    public abstract void CreateFavorites(ArrayList users, int threadID);
           
    public abstract void DeleteFavorites(int userID, ArrayList deleteList);
           
    #endregion
    2. Data Providers\SqlDataProvider\SqlDataProvider.cs增加实现方法
    #region #### 收藏夹 #### by venjiang 0912
           
    /// <summary>
           
    /// 追加主题到收藏夹
           
    /// </summary>
           
    /// <param name="userID">用户ID</param>
           
    /// <param name="threadID">主题ID</param>
            public override void CreateFavorites(int userID,int threadID)
            {
               
    using( SqlConnection myConnection = GetSqlConnection() )
                {
                    SqlCommand myCommand
    = new SqlCommand(databaseOwner + ".forums_Favorites_CreateDelete", myConnection);
                    myCommand.CommandType
    = CommandType.StoredProcedure;

                    myCommand.Parameters.Add(
    "@Action", SqlDbType.Bit).Value = DataProviderAction.Create;
                    myCommand.Parameters.Add(
    "@UserID", SqlDbType.Int);
                    myCommand.Parameters.Add(
    "@ThreadID", SqlDbType.Int);

                    myConnection.Open();
                    myCommand.Parameters[
    "@UserID"].Value = userID;
                    myCommand.Parameters[
    "@ThreadID"].Value = threadID;

                    myCommand.ExecuteNonQuery();
                }
            }
           
    /// <summary>
           
    /// 从收藏夹中删除主题
           
    /// </summary>
           
    /// <param name="userID">用户ID</param>
           
    /// <param name="deleteList">删除列表</param>
            public override void DeleteFavorites(int userID, ArrayList deleteList)
            {

               
    // Create Instance of Connection and Command Object
                using( SqlConnection myConnection = GetSqlConnection() )
                {
                    SqlCommand myCommand
    = new SqlCommand(databaseOwner + ".forums_Favorites_CreateDelete", myConnection);
                    myCommand.CommandType
    = CommandType.StoredProcedure;

                    myCommand.Parameters.Add(
    "@Action", SqlDbType.Int).Value = DataProviderAction.Delete;
                    myCommand.Parameters.Add(
    "@UserID", SqlDbType.Int).Value = userID;
                    myCommand.Parameters.Add(
    "@ThreadID", SqlDbType.Int);

                   
    // Open the connection
                    myConnection.Open();

                   
    // Add multiple times
                   
    //
                    foreach (int threadID in deleteList)
                    {
                        myCommand.Parameters[
    "@ThreadID"].Value = threadID;

                        myCommand.ExecuteNonQuery();

                    }
                }
            }
           
    #endregion
    3.在Data Providers\SqlDataProvider\SqlDataProvider.cs修改GetThreads方法,以支持收藏功能
    #region #### Threads ####
           
    // 增加贴子收藏 by venjiang 0911
            public override ThreadSet GetThreads(
                   
    int forumID,
                   
    int pageIndex,
                   
    int pageSize,
                   
    int userID,
                    DateTime threadsNewerThan,
                    SortThreadsBy sortBy,
                    SortOrder sortOrder,
                    ThreadStatus threadStatus,
                    ThreadUsersFilter userFilter,
                   
    bool activeTopics,
                   
    bool unreadOnly,
                   
    bool unansweredOnly,
                   
    bool returnRecordCount,
                   
    // 增加新参数,是否仅显示收藏的主题
                    bool favoriteOnly
                )
            {

               
    // Create Instance of Connection and Command Object
               
    //
                using( SqlConnection connection = GetSqlConnection() ) {
                    SqlCommand command
    = new SqlCommand(databaseOwner + ".forums_Threads_GetThreadSet", connection);
                    command.CommandType
    = CommandType.StoredProcedure;

                    ThreadSet threadSet            
    = new ThreadSet();
                    StringBuilder sqlCountSelect   
    = new StringBuilder("SELECT count(T.ThreadID) ");     
                    StringBuilder sqlPopulateSelect
    = new StringBuilder("SELECT T.ThreadID, HasRead = ");
                    StringBuilder fromClause       
    = new StringBuilder(" FROM " + this.databaseOwner + ".forums_Threads T ");
                    StringBuilder whereClause      
    = new StringBuilder(" WHERE ");
                    StringBuilder orderClause      
    = new StringBuilder(" ORDER BY ");

                   
    // 增加收藏判断 by venjiang 0911
                    if (favoriteOnly == true)
                    {
                        fromClause.Append(
    "," + this.databaseOwner + ".forums_Favorites Fav ");
                    }

                   
    // Ensure DateTime is min value for SQL
                   
    //
                    threadsNewerThan = SqlDataProvider.GetSafeSqlDateTime(threadsNewerThan);

                   
    // Construct the clauses
                    #region Constrain Forums

                   
    // Contrain the selectivness to a set of specified forums. The ForumID is our
                   
    // clustered index so we want this to be first
                    if (forumID > 0) {
                        whereClause.Append(
    "T.ForumID = ");
                        whereClause.Append(forumID);
                    }
    else if (forumID < 0) {
                        whereClause.Append(
    "(T.ForumID = ");

                       
    // Get a list of all the forums the user has access to
                       
    //
                        ArrayList forumList = Forums.GetForums(userID, false, true);

                       
    for (int i = 0; i < forumList.Count; i++) {

                           
    if ( ((Forum) forumList[i]).ForumID > 0 ) {
                               
    if ( (i + 1) < forumList.Count) {
                                    whereClause.Append( ((Forum) forumList[i]).ForumID
    + " OR T.ForumID = ");
                                }
    else {
                                    whereClause.Append( ((Forum) forumList[i]).ForumID );
                                    whereClause.Append(
    ")");
                                }
                            }

                        }
                    }
    else {
                        whereClause.Append(
    "T.ForumID = 0 AND P.UserID = ");
                        whereClause.Append(userID);
                        whereClause.Append(
    " AND P.ThreadID = T.ThreadID ");
                        fromClause.Append(
    ", " + this.databaseOwner + ".forums_PrivateMessages P ");
                    }
                   
    #endregion

                   
    #region Constrain Date
                    whereClause.Append(
    " AND StickyDate >= '");
                    whereClause.Append( threadsNewerThan.ToString( System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.SortableDateTimePattern ));
                    whereClause.Append(
    " '");
                   
    #endregion

                   
    #region Constain Approval
                    whereClause.Append(
    " AND IsApproved = 1");
                   
    #endregion

                   
    #region Constrain Read/Unread
                   
    if (userID > 0) {
                        sqlPopulateSelect.Append(
    "(SELECT " + this.databaseOwner + ".HasReadPost(");
                        sqlPopulateSelect.Append(userID);
                        sqlPopulateSelect.Append(
    ", T.ThreadID, T.ForumID)) ");

                       
    if (unreadOnly) {
                            whereClause.Append(
    " AND " + this.databaseOwner + ".HasReadPost(");
                            whereClause.Append(userID);
                            whereClause.Append(
    ", T.ThreadID, T.ForumID) = 0");
                        }
                    }
    else {
                        sqlPopulateSelect.Append(
    "0");
                    }
                   
    #endregion

                   
    #region Unanswered topics
                   
    if (unansweredOnly) {
                        whereClause.Append(
    " AND TotalReplies = 0 AND IsLocked = 0");
                    }
                   
    #endregion

                   
    #region Active topics
                   
    // 热门贴子
                    if (activeTopics) {
                        whereClause.Append(
    " AND TotalReplies > 2 AND IsLocked = 0 AND TotalViews > 50");
                    }
                   
    #endregion

                   
    #region 收藏
                   
    // 尽显示收藏的主题
                    if (favoriteOnly)
                    {
                        whereClause.Append(
    " AND T.ThreadID = Fav.ThreadID AND Fav.UserID = ");
                        whereClause.Append(userID);
                    }
                   
    #endregion


                   
    #region Users filter
                   
    if (userFilter != ThreadUsersFilter.All)
                    {

                       
    if ((userFilter == ThreadUsersFilter.HideTopicsParticipatedIn) || (userFilter == ThreadUsersFilter.HideTopicsNotParticipatedIn)) {

                            whereClause.Append(
    " AND ");
                            whereClause.Append(userID);

                           
    if (userFilter == ThreadUsersFilter.HideTopicsNotParticipatedIn)
                                whereClause.Append(
    " NOT");

                            whereClause.Append(
    " IN (SELECT UserID FROM " + this.databaseOwner + ".forums_Posts P WHERE P.ThreadID = T.ThreadID)");

                        }
    else {

                           
    if (userFilter == ThreadUsersFilter.HideTopicsByNonAnonymousUsers)
                                whereClause.Append(
    " AND 0 NOT");
                           
    else
                                whereClause.Append(
    " AND 0");

                            whereClause.Append(
    "IN (SELECT UserID FROM " + this.databaseOwner + ".forums_Posts P WHERE ThreadID = T.ThreadID AND P.UserID = 0)");
                        }
                    }
                   
    #endregion

                   
    #region Thread Status
                   
    if (threadStatus != ThreadStatus.NotSet) {
                       
    switch (threadStatus) {
                           
    case ThreadStatus.Open:
                                whereClause.Append(
    " AND ThreadStatus = 0");
                               
    break;

                           
    case ThreadStatus.Closed:
                                whereClause.Append(
    " AND ThreadStatus = 0");
                               
    break;

                           
    case ThreadStatus.Resolved:
                                whereClause.Append(
    " AND ThreadStatus = 0");
                               
    break;

                           
    default:
                               
    break;
                        }
                    }
                   
    #endregion

                   
    #region Order By
                   
    switch (sortBy) {
                       
    case SortThreadsBy.LastPost:
                           
    if (sortOrder == SortOrder.Ascending) {
                               
    if (activeTopics || unansweredOnly)
                                    orderClause.Append(
    "ThreadDate");
                               
    else
                                orderClause.Append(
    "IsSticky, StickyDate");
                            }
    else {
                               
    if (activeTopics || unansweredOnly)
                                    orderClause.Append(
    "ThreadDate DESC");
                           
    else
                                orderClause.Append(
    "IsSticky DESC, StickyDate DESC");
                            }
                           
    break;

                       
    case SortThreadsBy.TotalRatings:
                           
    if (sortOrder == SortOrder.Ascending)
                                orderClause.Append(
    "TotalRatings");
                           
    else
                                orderClause.Append(
    "TotalRatings DESC");
                           
    break;
               
                       
    case SortThreadsBy.TotalReplies:
                           
    if (sortOrder == SortOrder.Ascending)
                                orderClause.Append(
    "TotalReplies");
                           
    else
                                orderClause.Append(
    "TotalReplies DESC");
                           
    break;

                       
    case SortThreadsBy.ThreadAuthor:
                           
    if (sortOrder == SortOrder.Ascending)
                                orderClause.Append(
    "PostAuthor DESC");
                           
    else
                                orderClause.Append(
    "PostAuthor");
                           
    break;

                       
    case SortThreadsBy.TotalViews:
                           
    if (sortOrder == SortOrder.Ascending)
                                orderClause.Append(
    "TotalViews");
                           
    else
                                orderClause.Append(
    "TotalViews DESC");
                           
    break;
                    }
                   
    #endregion

                   
    // Build the SQL statements
                    sqlCountSelect.Append(fromClause.ToString());
                    sqlCountSelect.Append(whereClause.ToString());

                    sqlPopulateSelect.Append(fromClause.ToString());
                    sqlPopulateSelect.Append(whereClause.ToString());
                    sqlPopulateSelect.Append(orderClause.ToString());

                   
    // Add Parameters to SPROC
                   
    //
                    command.Parameters.Add("@ForumID", SqlDbType.Int).Value = forumID;
                    command.Parameters.Add(
    "@PageIndex", SqlDbType.Int, 4).Value = pageIndex;
                    command.Parameters.Add(
    "@PageSize", SqlDbType.Int, 4).Value = pageSize;
                    command.Parameters.Add(
    "@sqlCount", SqlDbType.NVarChar, 4000).Value = sqlCountSelect.ToString();
                    command.Parameters.Add(
    "@sqlPopulate", SqlDbType.NVarChar, 4000).Value = sqlPopulateSelect.ToString();
                    command.Parameters.Add(
    "@UserID", SqlDbType.Int).Value = userID;
                    command.Parameters.Add(
    "@ReturnRecordCount", SqlDbType.Bit).Value = returnRecordCount;

                   
    // Execute the command
                    connection.Open();
                    SqlDataReader dr
    = command.ExecuteReader();

                   
    // Populate the ThreadSet
                   
    //
                    while (dr.Read()) {

                       
    // Add threads
                       
    //
                        if (forumID == 0)
                            threadSet.Threads.Add( ForumsDataProvider.PopulatePrivateMessageFromIDataReader (dr) );
                       
    else
                            threadSet.Threads.Add( ForumsDataProvider.PopulateThreadFromIDataReader(dr) );

                    }

                   
    // Do we need to return record count?
                   
    //
                    if (returnRecordCount) {

                        dr.NextResult();

                        dr.Read();

                       
    // Read the total records
                       
    //
                        threadSet.TotalRecords = (int) dr[0];

                    }

                   
    // Get the recipients if this is a request for
                   
    // the private message list
                    if ((forumID == 0) && (dr.NextResult()) ) {
                        Hashtable recipientsLookupTable
    = new Hashtable();

                       
    while(dr.Read()) {
                           
    int threadID = (int) dr["ThreadID"];

                           
    if (recipientsLookupTable[threadID] == null) {
                                recipientsLookupTable[threadID]
    = new ArrayList();
                            }

                            ((ArrayList) recipientsLookupTable[threadID]).Add(ForumsDataProvider.PopulateUserFromIDataReader(dr) );
                        }

                       
    // Map recipients to the threads
                       
    //
                        foreach (PrivateMessage thread in threadSet.Threads) {
                            thread.Recipients
    = (ArrayList) recipientsLookupTable[thread.ThreadID];
                        }

                    }


                    dr.Close();
                    connection.Close();

                   
    return threadSet;
                }
            }

           
    #endregion

    八.增加新方法
    在Components\Threads.cs增加新的重载方法,以不必修改原来的方法调用.
    // 为了不影响以前的程序,单独加一个重载方法,以获得收藏夹主题
            public static ThreadSet GetThreads(int forumID, int pageIndex, int pageSize, int userID, DateTime threadsNewerThan, SortThreadsBy sortBy, SortOrder sortOrder, ThreadStatus threadStatus, ThreadUsersFilter userFilter, bool activeTopics, bool unreadOnly, bool unansweredOnly, bool returnRecordCount,bool favoriteOnly) // 多了一个参数favoriteOnly
            {
                ForumContext forumContext
    = ForumContext.Current;
               
    string anonymousKey = "Thread-" + forumID + pageSize.ToString() + pageIndex.ToString() + threadsNewerThan.DayOfYear.ToString() + sortBy + sortOrder + activeTopics.ToString() + unansweredOnly.ToString() + favoriteOnly.ToString();

                ThreadSet threadSet;

               
    // If the user is anonymous take some load off the db
               
    //
                if (userID == 0)
                {
                   
    if (forumContext.Context.Cache[anonymousKey] != null)
                       
    return (ThreadSet) forumContext.Context.Cache[anonymousKey];
                }

               
    // Create Instance of the IDataProvider
               
    //
                ForumsDataProvider dp = ForumsDataProvider.Instance();

               
    // Get the threads
               
    //
                threadSet = dp.GetThreads(forumID, pageIndex, pageSize, userID, threadsNewerThan, sortBy, sortOrder, threadStatus, userFilter, activeTopics, unreadOnly, unansweredOnly, returnRecordCount,favoriteOnly);

               
    if (userID == 0)
                    forumContext.Context.Cache.Insert(anonymousKey, threadSet,
    null, DateTime.Now.AddMinutes(2), TimeSpan.Zero, CacheItemPriority.Low, null);

               
    return threadSet;
            }

    九.业务逻辑层
    Components目录中增加Favorites.cs,实现主题的增加删除方法
    public static void AddFavoritesPost (int userID,int threadID) {

                ForumsDataProvider dp
    = ForumsDataProvider.Instance();

                dp.CreateFavorites(userID, threadID);

            }
           
    /// <summary>
           
    /// 删除收藏
           
    /// </summary>
           
    /// <param name="userID">用户ID</param>
           
    /// <param name="deleteList">删除列表</param>
            public static void DeleteFavorites (int userID, ArrayList deleteList) {

               
    //
                ForumsDataProvider dp = ForumsDataProvider.Instance();

                dp.DeleteFavorites(userID, deleteList);

            }

    十.表现层调用
    1.收藏夹主视图加载收藏主题列表
        threadSet
    = Threads.GetThreads(forumID, pager.PageIndex, pager.PageSize, Users.GetUser().UserID, dateFilterValue, threadSortddl.SelectedValue, sortOrderddl.SelectedValue, ThreadStatus.NotSet, ThreadUsersFilter.All, false, hideReadPosts.SelectedValue, false, true,true);
    注意最后一个参数是true,即返回收藏夹的数据集。
    2.增加主题到收藏夹
        Favorites.AddFavoritesPost(user.UserID,post.ThreadID);
        HttpContext.Current.Response.Redirect(Globals.ApplicationPath
    +"/MyFavoritesAdd.aspx",true);
    3.删除收藏的主题
        Favorites.DeleteFavorites(…)

    发表于 @ 2006年10月13日 22:54 | 评论 (458)

    模拟Asp.Net Forums 2.0 数据提供者类

    using System;

    using System.Reflection;

     

    namespace AbstractClass

    {

        //===============================================================

        // 模拟Asp.Net Forums 2.0 数据提供者类实现,

        // 以实现多数据库支持特性.

        // 2004.8.2 by venjiang.

        // ==============================================================

        #region 主程序调用

        class Class1

        {

            [STAThread]

            static void Main(string[] args)

            {

                // 所有方法调用,都在BaseAbstact类进行,不涉及子类调用.

                // 这样只要派生类(SubClass)能够重写基类相应方法就可以了.

     

                // 调用基类静态方法

                BaseAbstract.BaseOut();

               

                // 调用派生类SubClassA

                BaseAbstract ba=BaseAbstract.Instance("AbstractClass.SubClassA", "Power by venjiang.");

                ba.BaseOut1();

                ba=BaseAbstract.Instance("AbstractClass.SubClassA", "venjiang", 28);

                ba.BaseOut2();

               

                // 调用派生类SubClassB

                ba=BaseAbstract.Instance("AbstractClass.SubClassB", "Power by venjiang.");

                ba.BaseOut1();

                ba=BaseAbstract.Instance("AbstractClass.SubClassB", "venjiang", 28);

                ba.BaseOut2();

               

                Console.Read();

            }

        }

        #endregion

     

        #region 相当于ForumsDataProvider类

        public abstract class BaseAbstract

        {

            public static BaseAbstract Instance(string subClassType, string name)

            {

                Type myType=null;

     

                // 获取派生类的类型,在Forums2中subClassType这个类型由Web.config文件中<providers>下的type指定.

                myType = Type.GetType( subClassType );

                // 构建构造函数参数类型数组

                Type[] types = new Type[1];

                types[0] = typeof(string);

                // 获取指定参数的派生类的构造函数

                ConstructorInfo ci = myType.GetConstructor(types);

     

                // 指定派生类参数值

                object[] paramArray = new object[1];

                paramArray[0] = name;

     

                return (BaseAbstract)ci.Invoke(paramArray);

            }

     

            public static BaseAbstract Instance(string subClassType, string name, int height)

            {

                Type myType=null;

     

                // 获取派生类的类型

                myType = Type.GetType( subClassType );

                // 构建构造函数参数类型数组

                Type[] types = new Type[2];

                types[0] = typeof(string);

                types[1] = typeof(int);

                // 获取指定参数的派生类的构造函数

                ConstructorInfo ci = myType.GetConstructor(types);

     

                // 指定派生类参数值

                object[] paramArray = new object[2];

                paramArray[0] = name;

                paramArray[1] = height;

     

                return (BaseAbstract)ci.Invoke(paramArray);

            }

           

            public static void BaseOut()

            {

    //          Type myType=null;

    //          myType = Type.GetType("AbstractClass.SubClassA");

                Console.WriteLine("[基类]这是抽象类的静态方法");

    //          Console.WriteLine("测试{0}",myType.ToString());

            }

            public abstract void BaseOut1();

            public abstract void BaseOut2();

        }

        #endregion

     

        #region 相当于SqlDataProvider类

        public class SubClassA:BaseAbstract

        {

           

            private string _name="";

            private int _height=0;

     

            public SubClassA(string name)

            {

                _name=name;

            }

            public SubClassA(string name,int height)

            {

                _name=name;

                _height=height;

            }

     

            public override void BaseOut1()

            {

                Console.WriteLine("[派生类A]重写基类BaseOut1方法,"+ _name);

     

            }

            public override void BaseOut2()

            {

                Console.WriteLine("[派生类A]重写基类BaseOut2方法,"+ _name + "," + _height.ToString());

     

            }

       

        }

        #endregion

     

        #region  相当于其它数据库支持类

        public class SubClassB:BaseAbstract

        {

           

            private string _name="";

            private int _height=0;

     

            public SubClassB(string name)

            {

                _name=name;

            }

            public SubClassB(string name,int height)

            {

                _name=name;

                _height=height;

            }

     

            public override void BaseOut1()

            {

                Console.WriteLine("[派生类B]重写基类BaseOut1方法,"+ _name);

     

            }

            public override void BaseOut2()

            {

                Console.WriteLine("[派生类B]重写基类BaseOut2方法,"+ _name + "," + _height.ToString());

     

            }

       

        }

        #endregion

    }

    发表于 @ 2006年10月13日 22:49 | 评论 (480)

    增加Pager控件没有的跳转页功能

    Pager类,用于分页, Controls\Utility\Pager.cs

    首先增加成员变量:

            /// venjiang:增加跳转页输入文本框

            /// </summary>

            TextBox gotoPage;

            /// <summary>

            /// venjiang:增加跳转按钮

            /// </summary>

            LinkButton gotoButton;

    其次增加控件:

    /// <summary>

            /// 跳转按钮

            /// </summary>

            void AddGotoButton()

            {

                this.gotoButton=new LinkButton();

                this.gotoButton.ID="GoTo";

                this.gotoButton.Text="Go";

                this.gotoButton.Click += new System.EventHandler(PageIndex_Click);

                Controls.Add(gotoButton);

            }

     

            /// <summary>

            /// 增加跳转页输入框

            /// </summary>

            void AddGotoPage()

            {

                this.gotoPage=new TextBox();

                this.gotoPage.Width=30;

                this.gotoPage.ID="GoToPage";

                //this.gotoPage.Text="3";

                this.gotoPage.TextChanged += new System.EventHandler(PageText_Change);

                //this.gotoPage.EnableViewState=true;

                Controls.Add(gotoPage);

            }

    增加跳转页文本框文本改变事件:

        void PageText_Change(Object sender,EventArgs e)

            {

                int i = 1;

                try

                {

                    i = Convert.ToInt32(this.gotoPage.Text.Trim().ToString());

                   

                    if(i < 1)

                    {

                        i = 1;

                        this.gotoPage.Text="1";

                    }

     

                    if(i > CalculateTotalPages())

                    {

                        i = CalculateTotalPages();

                        this.gotoPage.Text=i.ToString();

                    }

                }

                catch

                {

                    this.gotoPage.Text="";

                    return;

                }

                this.gotoButton.CommandArgument = (i-1).ToString();

               

            }

    增加呈现方法:

            void RenderGotoPage(HtmlTextWriter writer)

            {

                Literal l,m;

     

                l = new Literal();

                l.Text = "&nbsp;&nbsp;";

                l.RenderControl(writer);

                this.gotoPage.RenderControl(writer);

                this.gotoButton.RenderControl(writer);

                m = new Literal();

                m.Text = "&nbsp;";

                m.RenderControl(writer);

            }

     

    最后将所创建的方法分别添加到相应用方法中:

    CreateChildControls()方法尾部,增加this.AddGotoPage();this.AddGotoButton();

    Render()方法尾部,增加this.RenderGotoPage(writer);

    发表于 @ 2006年10月13日 22:46 | 评论 (428)

    2006年10月11日

    关于Cache的疑惑

    Cache.Insert("CacheKey", value, null, DateTime.Now.AddSeconds(30), TimeSpan.Zero, CacheItemPriority.Normal, null);

    Cache.Insert("CacheKey", value, null, DateTime.Now.AddSeconds(30), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);

    前者很少有命中.
    后者才是按时间命中.

    System.Web.Caching.Cache.NoSlidingExpiration实际也是设置为TimeSpan.Zero.
    MSDN如是说:
    使用后,该字段将 slidingExpiration 参数设置成 TimeSpan.Zero 字段,该字段具有常数值零。缓存项依照与 Insert 或 Add 方法调用相关的 absoluteExpiration 参数设置过期。

    无法同时设置 absoluteExpiration 和 slidingExpiration 参数。如果要让缓存项在特定时间过期,可将 absoluteExpiration 参数设置为特定时间,并将 slidingExpiration 参数设置为 NoSlidingExpiration。

    如果要让缓存项自最后一次访问该项后的某段时间之后过期,可将 slidingExpiration 参数设置为过期间隔,并将 absoluteExpiration 参数设置为 NoAbsoluteExpiration。

    MSDN:示例
    Cache.Insert("DSN", connectionString, null, DateTime.Now.AddMinutes(2), TimeSpan.Zero, CacheItemPriority.High, onRemove);
     

    而这种方法,用户访问后,立即过期,缓存实际上根本无法命中.
    MSDN上的示例都是如此.

    ?????
     

    发表于 @ 2006年10月11日 16:35 | 评论 (596)