为BlogEngine.NET增加日志点击数

28. 三月 2009

由于是给日志增加点击数,所以我们需要修改BlogEngine.Core.Post类,为它增加一个属性。

private int _ViewCount;
/// <summary>
/// Gets or sets the view count of post
/// </summary>
public int ViewCount
{
    
get { return _ViewCount; }
    
set
    {
        
if (_ViewCount != value) MarkChanged("ViewCount");
        _ViewCount
= value;
    }
}

再用SharpPlus Sqlite Developer打开BlogEngine使用的SQLite数据,在“be_Posts”表中增加一个“ViewCount”字段,数据类型为“INTEGER”,默认值设为“0”。

 

然后找到BlogEngine.Core.Providers.BlogProvider.cs类,在public abstract void DeletePost(Post post);后面添加

public abstract void UpdateViewCount(Guid id);

再找到BlogEngine.Core.Providers.BlogService.cs类,在public static void DeletePost(Post post){}方法后面添加

public static void UpdateViewCount(Guid id)
{
    LoadProviders();
    _provider.UpdateViewCount(id);
}

 在BlogEngine.Core.Providers.DbBlogProvider.cs类中的public override void DeletePost(Post post){}方法后添加

public override void UpdateViewCount(Guid id)
{
    
string connString = ConfigurationManager.ConnectionStrings[connStringName].ConnectionString;
    
string providerName = ConfigurationManager.ConnectionStrings[connStringName].ProviderName;
    DbProviderFactory provider
= DbProviderFactories.GetFactory(providerName);

    
using (DbConnection conn = provider.CreateConnection())
    {
        conn.ConnectionString
= connString;
        conn.Open();
        
using (DbCommand cmd = conn.CreateCommand())
        {
            
string sqlQuery = "UPDATE " + tablePrefix + "Posts SET ViewCount = ViewCount+1 " +
                                
"WHERE PostID = @id";
            
if (parmPrefix != "@")
                sqlQuery
= sqlQuery.Replace("@", parmPrefix);
            cmd.CommandText
= sqlQuery;
            cmd.CommandType
= CommandType.Text;

            DbParameter dpID
= provider.CreateParameter();
            dpID.ParameterName
= parmPrefix + "id";
            dpID.Value
= id.ToString();
            cmd.Parameters.Add(dpID);

            cmd.ExecuteNonQuery();
        }
    }
}

修改BlogEngine.Core.Providers.DbBlogProvider.cs类中的public override Post SelectPost(Guid id)方法,加入post.ViewCount值的获取,类似post.Raters = rdr.GetInt32(9);

再在BlogEngine.Core.Post.cs中添加一个静态方法:

public static void UpdateViewCount(Guid id)
{
    Posts.Find(
delegate(Post p) { return p.Id == id; }).ViewCount++;   //更新内存数据  
    BlogService.UpdateViewCount(id);  //更新数据库记录  
}

重新编译BlogEngine.Core,如果编译器报这样的错误:

错误 1 “BlogEngine.Core.Providers.XmlBlogProvider”不实现继承的抽象成员

我们还需要在BlogEngine.Core/Providers/XmlProvider/Posts.cs文件中的public override void DeletePost(Post post){}方法后添加

public override void UpdateViewCount(Guid id)
{ }

如果使用的是Xml存储数据,则在这里添加相应的增加点击数的方法。

这样就能顺利地重新编译BlogEngine.Core了。

接下来修改BlogEngine.Web中的文件post.aspx.cs。在protected void Page_Init(object sender, EventArgs e){}方法体内中的插入“Post.UpdateViewCount(this.Post.Id);”。

if (Request.QueryString["id"] != null && Request.QueryString["id"].Length == 36)
{
    Guid id
= new Guid(Request.QueryString["id"]);
    
this.Post = Post.GetPost(id);

    
if (Post != null)
    {
        
//在这里插入下面这句话
    Post.UpdateViewCount(this.Post.Id);
        
//以下是原文
    if (!this.Post.IsVisible && !Page.User.Identity.IsAuthenticated)
            Response.Redirect(Utils.RelativeWebRoot
+ "error404.aspx", true);
        ...
    }
}

最后,只在要在theme的PostView.ascx中需要显示点击数的地方插入“<%=Post.ViewCount %>”即可。

本文转自:http://blog.moozi.net/archives/2009/02/06/add-viewcount-to-blogengine.aspx

BlogEngine

BlogEngine.net插件-代码格式化加亮

15. 十一月 2008

      在使用BlogEngine.net博客程序的时候,发现里面有一个代码格式化加亮的插件,叫"CodeFormatterExtension”。但是点击"view",发现显示“Source for [X:\你的路径\BlogEngine.NET\App_Code\Extensions\CodeFormatterExtension.cs] not found ”,出现没有找到文件的错误,再查看我的“App_Code\Extensions”文件夹,发现有一个叫做"CodeFormatter”的文件夹。查了相关的资料,发现只要把"CodeFormatter”的文件夹里的"CodeFormatter.cs”文件移动到“App_Code\Extensions”文件夹,并更名为“CodeFormatterExtension.cs”就可以正常使用了。目前只支持c#,javascript,vb,t-sql等,格式如[code:c#][/code](需要将方括号转换为半角)。测试如下:

class HelloWorldApp
{
    static void Main()
    {
        System.Console.WriteLine("Hello, world!");
    }
}

.NET技术, BlogEngine

BlogEngine.NET无法发送成功Email和联系留言的解决之道

8. 十一月 2008

本人使用BlogEngine.NET一个多星期了,最近发现网站中的联系页面(contact me)中发送的留言信息,我的邮箱根本无法收到,我的邮箱是126.com的,查了一下,发现后台高级设置里的邮箱测试发送是正常,那么问题就出在发送的代码上了。

经本人一条条地测试后,问题出在contact.aspx.cs文件中的第94行"mail.Sender = mail.ReplyTo;"中,mail.Sender是发件人地址,而给它的值是回复邮件地址,从而造成邮箱发送时验证失败,只要把这段代码改成"mail.Sender = mail.From;"或是改成"mail.Sender = new MailAddress(BlogSettings.Instance.Email, BlogSettings.Instance.SmtpUserName);"就可以了,保存编译后再试试,你的邮箱是不是可以收你发送的测试数据了呢!

另外,contact.aspx.cs文件中的第92行代码"mail.From = new MailAddress(BlogSettings.Instance.Email, name);"有逻辑上的问题,当然不会出错,不影响使用,此段代码中的BlogSettings.Instance.Email是站长自已的Email,但对应的name确是留言都输入的名字,有点文不对题了,所以本人见意应该改成"mail.From = new MailAddress(BlogSettings.Instance.Email, BlogSettings.Instance.SmtpUserName);"更为合适一些,如本人理解有误,请大家多多指正!

BlogEngine ,

BlogEngine.NET1.4.5.0使用Sqlite数据库出现丢失分类和Tags的解决办法

1. 十一月 2008

BlogEngine.NET是一个国外的开源的blog系统,功能非常强大,与wordpress有点相似,最新版本提供了对Sqlite的支持,本人对Sqlite数据库比较有好感,兴冲冲地升级成Sqlite后,在使用中发现博客的分类和Tags经常无故地丢失,经本人检查后发现,在Sqlite数据库中部份表格中的ID字段是乱码,BlogEngine中的ID字段数据是由System.Guid生成的,是一串英文字符,不太可能是乱码,如be_Categories表中的CategoryID字段和be_PostTag表中的postTagID,但be_Posts表中的PostID是正常的,同样的数据出现不同的结果,问题就出现在这里。

经过我对源代码的分析对比,发现问题出现在Guid上,在将数据存入数据库时,没有将guid类型的数据加上".ToString()"转成String字符串,就会出现乱码,主要在BlogEngine.Core目录里面,将BlogEngine.Core目录里有所文件中由Guid成生的ID传值时都加上".ToString()",保存编译后一切正常了!代码如图(取自DbBlogProvider.cs):

BlogEngine ,

[BlogEngine插件]对日志进行加密

31. 十月 2008
这里的对日志加密是指输入正确密码以后才能正常访问。
示例:
http://www.yibin001.com/Archives/6035.aspx
密码:123456
针对于BlogEngine来说,可以用它丰富的插件机制来实现。


首先明确,完成这个插件需要做哪些工作:
1、数据表结构的变化。要增加密码项,“密码”字段当然是少不了了。
2、表结构的变化势必会引起Post实体类属性的变化。
3、Post.Serving时触发事件,该事件负责针对性的改变e.Body
4、认证的实现。
这里我用的是SqlServer数据库,打开be_Posts表,执行以下语句

  1. ALTER TABLE dbo.be_Posts   
  2. ADD AccessPassword VARCHAR(100) NOT NULL DEFAULT ''  
  3. GO  

对应地在BlogEngine.Core.Post中增加属性AccessPassword
  1. private string _AccessPassword = string.Empty;   
  2.         public string AccessPassword   
  3.         {   
  4.             get { return _AccessPassword; }   
  5.             set {   
  6.                 if (_AccessPassword != value) MarkChanged("AccessPassword");   
  7.                 _AccessPassword = value;   
  8.             }   
  9.         }  

这里的AccessPassword不为空表明该日志需要密码才能访问。当然,这里还得修改相应的数据访问层代码,来初始化AccessPassword字段。这里略去。
下一步编写插件,针对Post.Serving事件编写,全部代码:
  1.   
  2. [Extension("加密日志","1.0","yibin")]   
  3. public class ZPostAccessExtension : System.Web.SessionState.IRequiresSessionState   
  4. {   
  5.     string cookiekey = string.Empty;   
  6.     public ZPostAccessExtension()   
  7.     {   
  8.         Post.Serving += new EventHandler<ServingEventArgs>(Post_Serving);   
  9.     }   
  10.   
  11.     void Post_Serving(object sender, ServingEventArgs e)   
  12.     {   
  13.         Post p = sender as Post;   
  14.            
  15.         if (HttpContext.Current.User.IsInRole("administrators") || HttpContext.Current.User.Identity.Name == p.Author)   
  16.             return;   
  17.         cookiekey = "POSTACCESS_" + p.Id;   
  18.        //这里很关键,用Session来判断当前用户没有权限访问,如果指定的session存在,则直接退出,否则更改e.Body值。   
  19.         if (HttpContext.Current.Session[cookiekey] != null)   
  20.         {   
  21.                 return;   
  22.         }   
  23.         if (!string.IsNullOrEmpty(p.AccessPassword))   
  24.         {   
  25.             if (e.Location == ServingLocation.PostList)   
  26.             {   
  27.                 e.Body = "加密日志,您无权查看";   
  28.             }   
  29.             else  
  30.             {   
  31.                 e.Body = string.Format(@"<p class=""AccessPassword"">加密日志,请输入密码查阅</p><input type=""password"" name=""AccessPassword_{0}"" id=""AccessPassword_{0}"" class=""AccessPassword"" /><input type=""button"" value=""确定"" title=""确定"" onclick=""Check();""/>", p.PostIdentity);   
  32.                 e.Body = e.Body.Replace("<""<").Replace(">"">");  //这里要对已经HtmlEncode后的字符进行还原,否则显示不正确。   
  33.             }   
  34.         }   
  35.     }   
  36. }  


接下来就是实现认证这一步,我采用的是实现ICallbackEventHandler接口来进行无刷新操作。
先看很简单的js代码
  1. <script type="text/javascript">   
  2. var accessMessage = document.getElementById('AccessMessage');   
  3. function Check()   
  4.    {   
  5.         accessMessage.style.display='block';   
  6.        var pwd = '';   
  7.        var panel = document.getElementById('AccessPassword_<%=Post.PostIdentity %>');  //DOM找到密码输入框   
  8.        if(panel) {   
  9.            pwd = panel.value;   
  10.        }   
  11.        if(pwd==''){   
  12.        accessMessage.innerHTML='密码不能为空';   
  13.        panel.focus();   
  14.        return false;   
  15.        }   
  16.           accessMessage.innerHTML='正在验证......';   
  17.      <%= Page.ClientScript.GetCallbackEventReference(this,"pwd","checkCallback","")%>;   
  18.    }   
  19.       
  20.    function checkCallback(rValue) {   
  21.    if(rValue=='error')   
  22.    {   
  23.        accessMessage.style.display='block';   
  24.        accessMessage.innerHTML='密码认证失败';   
  25.        setTimeout(function(){accessMessage.style.display='none';},2000);   
  26.    }   
  27.    else{   
  28.    accessMessage.style.display='block';   
  29.        accessMessage.innerHTML='验证成功';   
  30.      setTimeout(function(){document.getElementById('entrybody_<%=Post.PostIdentity %>').innerHTML = rValue;},500);   
  31.      setTimeout(function(){accessMessage.style.display='none';},3000);   
  32.    }   
  33.    }   
  34.    function ServerError(error) {   
  35.        alert(error);   
  36.    }   
  37.    </script>  

.cs文件中的关于ICallbackEventHandler接口的实现
  1. #region ICallbackEventHandler 成员   
  2. protected string _callback = string.Empty;   
  3. string ICallbackEventHandler.GetCallbackResult()   
  4. {   
  5.     return _callback;   
  6. }   
  7.   
  8. void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)   
  9. {   
  10.     if (Post.AccessPassword == eventArgument.Trim())   
  11.     {   
  12.         string SessionKey = "POSTACCESS_" + Post.Id;   
  13.         HttpContext.Current.Session.Add(SessionKey, true);  //注意这里,当密码验证成功后写session   
  14.         string path = Utils.RelativeWebRoot + "themes/" + BlogSettings.Instance.Theme + "/PostView.ascx";   
  15.   
  16.         PostViewBase postView = (PostViewBase)LoadControl(path);   
  17.         postView.Post = Post;   
  18.         postView.Location = ServingLocation.SinglePost;   
  19.         _callback = postView.Body;   //此处仍然会执行Post.Serving 事件,但因为前面已经写入了Session,所以触发Post.Serving 事件时将直接返回日志内容。   
  20.         //因为我想每次访问日志都需要输密码,所以,当正确返回日志内容后,清除掉该Session   
  21.         HttpContext.Current.Session.Remove(SessionKey);   
  22.     }   
  23.     else  
  24.     {   
  25.         _callback = "error";   
  26.     }   
  27. }  
  28. #endregion  

OK,整个过程就是如此,很是简单吧。
同样的原理,可以实现类似于论坛的“回复后可见”同样的功能,如果想长时间维持日志的正常查看权,可将Session换成Cookie。
另外,BlogEngine默认在web.config中将enableSessionState设为了false,请一定要设为true,否则无法使用Session!
我就是没有认真看web.config,在Session的获取上大费周折。
本文转自:http://www.yibin001.com/Archives/6036.aspx

BlogEngine