WebSurfer's Home

トップ > Blog 2   |   ログイン
APMLフィルター

BlogEngine.NET 2.0 の Tag cloud の問題

by WebSurfer 2011年6月12日 21:19

Tag cloud の中のタグをクリックすると、通常はそのタグを持つ記事が選択されて表示されます。しかしながらバージョン 2.0 では、日本語のタグをクリックすると何も選択されない(従って表示もされない)という問題があります。

この問題は IE を使ったときに発生します。Firefox 4.0.1, Chrome 12.0.742.91, Opera 11.11 などでは問題ありませんでした。

原因は、IE が要求を Web サーバーに送るときクエリ文字列を URL エンコードしないためと、バージョン 2.0 の Core.Utils.RemoveIllegalCharacters メソッドで UrlEncode が HtmlEncode に変更されていたためです(SEO 対策だそうです)。

バージョン 2.0 の場合、Tag cloud の中に「日本語」というタグがあったとすると、そのリンクは以下のようになります(以下で、"日本語" は生の UTF-8 になります)。

http://surferonwww.info/BlogEngine2/?tag=/日本語

IE は、要求を送るときに、? の前までは URL エンコードしてから送信しますが、クエリ文字列はそのまま UTF-8 で送信します(バグ?)。それゆえ、サーバー側で Request.QueryString["tag"] では "/日本語" は正しく取得できません。

この問題を避けるため、tag も category と同様に、クエリ文字列ではなくファイル名に設定するように変更しました。以下のような感じです。

http://surferonwww.info/BlogEngine2/tag/日本語.aspx

こうすれば IE の場合でも "日本語" を URL エンコードしてから要求を送りますので、問題はなくなります。そのために変更しなければならないのは、概略以下の部分です。

  • URL 文字列を組み立ててタグのリンクに設定する部分
  • URL を書き換える UrlRewrite HTTP モジュール
  • 書き換えられた URL からタグ名を取得し関連する記事の一覧を表示する部分

具体的には以下のようにコードを変更しました。

widget/Tag cloud/widget.ascx.cs の LoadWidget メソッド

public override void LoadWidget()
{
  foreach (var key in this.WeightedList.Keys)
  {
    using (var li = new HtmlGenericControl("li"))
    {
      //li.InnerHtml = string.Format(
      //    LinkFormat,
      //    string.Format("{0}?tag=/{1}",
      //        Utils.RelativeWebRoot,
      //        Utils.RemoveIllegalCharacters(key)),
      //    this.WeightedList[key],
      //    "Tag: " + key,
      //    key);

      li.InnerHtml = string.Format(
        LinkFormat,
        string.Format("{0}tag/{1}", 
          Utils.RelativeWebRoot, 
          Utils.RemoveIllegalCharacters(key) + 
            BlogSettings.Instance.FileExtension),
        this.WeightedList[key],
        "Tag: " + Server.HtmlEncode(key),
        Server.HtmlEncode(key));

      this.ulTags.Controls.Add(li);
    }
  }
}

Core\Web\Controls\PostViewBase.cs の TagLinks メソッド

protected virtual string TagLinks(string separator)
{
  StateList<string> tags = this.Post.Tags;
  if (tags.Count == 0)
  {
    return null;
  }

  string[] tagStrings = new string[tags.Count];
  const string Link = "<a href=\"{0}/{1}\" rel=\"tag\">{2}</a>";

  //var path = Utils.RelativeWebRoot + "?tag=";
  //for (var i = 0; i < tags.Count; i++)
  //{
  //  var tag = tags[i];
  //  tagStrings[i] = string.Format(
  //    CultureInfo.InvariantCulture, 
  //    Link, 
  //    path, 
  //    HttpUtility.UrlEncode(tag), 
  //    HttpUtility.HtmlEncode(tag));
  //}

  string path = Utils.RelativeWebRoot + "tag";
  for (int i = 0; i < tags.Count; i++)
  {
    string tag = tags[i];
    tagStrings[i] = string.Format(
      CultureInfo.InvariantCulture, 
      Link, 
      path,
      Utils.RemoveIllegalCharacters(tag) + 
        BlogSettings.Instance.FileExtension, 
      HttpUtility.HtmlEncode(tag));
  }

  return string.Join(separator, tagStrings);
}

Core/Web/HttpModules/UrlRewrite.cs の RewriteTag メソッド

private static void RewriteTag(HttpContext context, string url)
{
  string tag = ExtractTitle(context, url);

  if (url.Contains("/FEED/"))
  {
    //context.RewritePath(
    //  string.Format("syndication.axd?tag={0}{1}", 
    //    tag, 
    //    GetQueryString(context)), 
    //  false);

    context.RewritePath(
      string.Format("syndication.axd?tag={0}{1}",
        context.Server.UrlEncode(tag), 
        GetQueryString(context)),
      false);
  }
  else
  {
    //context.RewritePath(
    //  string.Format("{0}?tag=/{1}{2}", 
    //    Utils.RelativeWebRoot, 
    //    tag, 
    //    GetQueryString(context)), 
    //  false);

    context.RewritePath(
      string.Format("{0}default.aspx?tag={1}{2}", 
        Utils.RelativeWebRoot,
        context.Server.UrlEncode(tag), 
        GetQueryString(context)), 
      false);
  }
}

default.aspx.cs の Page_Load メソッド

protected void Page_Load(object sender, EventArgs e)
{
  if (Page.IsCallback)
  {
    return;
  }

  if (Request.RawUrl.ToLowerInvariant().Contains("/category/"))
  {
    DisplayCategories();
  }
  else if (Request.RawUrl.
    ToLowerInvariant().Contains("/author/"))
  {
    DisplayAuthors();
  }
  // else if (Request.RawUrl.ToLowerInvariant().Contains("?tag="))
  else if (Request.RawUrl.ToLowerInvariant().Contains("/tag/"))
  {
    DisplayTags();
  }
  ....

default.aspx.cs の DisplayTags メソッド

private void DisplayTags()
{
  //if (!string.IsNullOrEmpty(Request.QueryString["tag"]))
  //{
  //  PostList1.ContentBy = ServingContentBy.Tag;
  //  PostList1.Posts = 
  //    Post.GetPostsByTag(Request.QueryString["tag"].
  //      Substring(1)).ConvertAll(
  //        new Converter<Post, IPublishable>(delegate(Post p) 
  //          { return p as IPublishable; }));
  //  base.Title = " All posts tagged '" + 
  //    Request.QueryString["tag"].Substring(1) + "'";
  //}

  if (!string.IsNullOrEmpty(Request.QueryString["tag"]))
  {
    PostList1.ContentBy = ServingContentBy.Tag;
    List<Post> posts =
      Post.GetPostsByTag(Request.QueryString["tag"]);
    PostList1.Posts =
      posts.ConvertAll(new Converter<Post, IPublishable>(
        p => p as IPublishable));
    if (posts.Count > 0)
    {
      foreach (string t in posts[0].Tags)
      {
        if (Utils.RemoveIllegalCharacters(t).Equals(
          Request.QueryString["tag"],
          StringComparison.OrdinalIgnoreCase))
        {
          base.Title = "
             All posts tagged '" + Server.HtmlEncode(t) + "'";
          break;
        }
      }
    }
    else
    {
      base.Title = 
        " All posts tagged '" + 
        Request.QueryString["tag"] + "'";
    }
  }
}

Core.Post.cs の GetPostsByTag メソッド

public static List<Post> GetPostsByTag(string tag)
{
  // RemoveIllegalCharacters not required
  //tag = Utils.RemoveIllegalCharacters(tag);

  var list =
    Posts.FindAll(
      p =>
        p.Tags.Any(t => Utils.RemoveIllegalCharacters(t).
          Equals(tag, StringComparison.OrdinalIgnoreCase)));

  return list;
}

Core\Web\Controls\PostViewBase.cs の DescriptionCharacters プロパティ

public int DescriptionCharacters 
{ 
  get 
  {
    int chars = 0;
    string url = 
      HttpContext.Current.Request.RawUrl.ToUpperInvariant();

    //if (url.Contains("/CATEGORY/") || url.Contains("?TAG=/"))
    if (url.Contains("/CATEGORY/") || url.Contains("/TAG/"))
    {
      if (BlogSettings.Instance.
        ShowDescriptionInPostListForPostsByTagOrCategory)
      {
        return BlogSettings.Instance.
          DescriptionCharactersForPostsByTagOrCategory;
      }
    }
    else
    {
      if (BlogSettings.Instance.ShowDescriptionInPostList)
      {
        return BlogSettings.Instance.DescriptionCharacters;
      }
    }
    return chars;
  }
}

User controls/PostList.ascx.cs の ShowExcerpt メソッド

private bool ShowExcerpt()
{
  string url = this.Request.RawUrl.ToUpperInvariant();

  //bool tagOrCategory = url.Contains("/CATEGORY/") || url.Contains("?TAG=/");

  bool tagOrCategory = 
    url.Contains("/CATEGORY/") || url.Contains("/TAG/");

  return BlogSettings.Instance.ShowDescriptionInPostList ||
    (BlogSettings.Instance.
        ShowDescriptionInPostListForPostsByTagOrCategory 
      && 
      tagOrCategory);
}

Tags:

BlogEngine.NET 2.0

About this blog

ここブログ2は日々の出来事、ブログ1はプログラミング関係のトピックスになっています。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar