タグ別アーカイブ: BlogEngine.NET

(メモ)BlogEngine.NET 2.5で日本語タイトルからのSlugの生成をマシにする

まだ完璧じゃないけど、メモということで。

admin/Posts/Add_entry.aspx.cs のRaiseCallbackEvent を改造する。

        /// <summary>
        /// Processes a callback event that targets a control.
        /// </summary>
        /// <param name="eventArgument">
        /// A string that represents an event argument to pass to the event handler.
        /// </param>
        public void RaiseCallbackEvent(string eventArgument)
        {
            if (eventArgument.StartsWith("_autosave"))
            {
                var fields = eventArgument.Replace("_autosave", string.Empty).Split(
                    new[] { ";|;" }, StringSplitOptions.None);
                Session["content"] = fields[0];
                Session["title"] = fields[1];
                Session["description"] = fields[2];
                Session["slug"] = fields[3];
                Session["tags"] = fields[4];
            }
            else
            {
                //butaman modify
                System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"[^a-zA-Z0-9_\-]");
                System.Text.RegularExpressions.Regex r2 = new System.Text.RegularExpressions.Regex(@"\-{2,}");
                System.Text.RegularExpressions.Regex r3 = new System.Text.RegularExpressions.Regex(@"(^\-|\-$)");
                var result = eventArgument.Trim();
                result = result.Replace(".", "-");
                result = Utils.RemoveIllegalCharacters(result);
                result =  Microsoft.VisualBasic.Strings.StrConv(result,  Microsoft.VisualBasic.VbStrConv.Narrow, 0);
                result = r.Replace(result, "-");
                result = r2.Replace(result, "-");
                result = r3.Replace(result, "");
                callback = result;
            }
        }

我ながら酷いコードだが、こんな感じ。

ただ、Slugを空欄にしてPostすると、従来通りのSlugになってしまう。毎回「Extract from title」リンクボタンを押さないといけないので面倒。根本的には、Utils.RemoveIllegalCharactersを弄る必要があるのだけど、めんどくさいからやらない。

BlogEngine.NETをリバースプロキシ環境で使う(Global.asaxを改造)

このBlogはリバースプロキシ環境下で動作している。フロントエンドはApache(blog.ebuta.net:80)で、バックエンドがIIS(blog.ebuta.net:8081)である。

さて、バックエンドのIISでBlogEngine.NET 2.5を動作させると、非常に困ったことが発生する。一部のメニューのリンク等がバックエンドのURLを指してしまうのだ。例えば、ホームへのリンク。こちらとしては「http://blog.ebuta.net/」を指して欲しいのに、実際に表示されるリンクは「http://blog.ebuta.net:8081/」を指してしまう。この問題点は リバースプロキシの確認 – kiyoeri BlogEngine でも指摘されている。この問題の原因は、BlogEngine.NETがリクエストのURLをもとに絶対URLを取得していることである。これをできるだけシンプルな方法で解決したい。

ソースを調べてみると、各テーマにおいて、絶対URLの取得に「Utils.AbsoluteWebRoot」を参照していることが分かる。ここで、修正方法は2つ考えられる。

  1. テーマを修正する
  2. Utils.AbsoluteWebRootを修正する

1はシンプルだが、根本的なところが治っていないので、他のところでボロが出そうである。となると、2のUtils.AbsoluteWebRootの修正であるが、実はUtilsクラスはコンパイル済のアセンブリ(DLL)の中にあり、修正にはVisualStudioを使ってソースからコンパイルし直す必要がある。別にコンパイルするのは構わないのだが、バージョンが上がるたびにコンパイルをしなおすのはいかにも面倒だ。他の方法がないか手がかりを探すため、まず、Utils.AbsoluteWebRootのソースを覗いてみる。

        /// <summary>
        ///     Gets the absolute root of the website.
        /// </summary>
        /// <value>A string that ends with a '/'.</value>
        public static Uri AbsoluteWebRoot
        {
            get
            {
                var context = HttpContext.Current;
                if (context == null)
                {
                    throw new WebException("The current HttpContext is null");
                }

                var absoluteurl = context.Items["absoluteurl"];
                if (absoluteurl == null)
                {
                    absoluteurl = new Uri(context.Request.Url.GetLeftPart(UriPartial.Authority) + RelativeWebRoot);
                    context.Items["absoluteurl"] = absoluteurl;
                }

                return absoluteurl as Uri;

            }
        }

 このソースを読む限り、リクエストごとに、最初はURLを元に絶対URLを作成し、以降は context.Items[“absoluteurl”]にキャッシュされるようになっている。つまり、AbsoluteWebRootが呼ばれる前(あるいは、テーマがレンダリングされる前)に、context.Items[“absoluteurl”]を設定してしまえばいいのである。そこで、Global.asaxを改変して、この処理を追加することにする。

Global.asaxのApplication_BeginRequestを見てみる。

    void Application_BeginRequest(object source, EventArgs e)
    {
        HttpApplication app = (HttpApplication)source;
        HttpContext context = app.Context;
        
        // Attempt to perform first request initialization
        FirstRequestInitialization.Initialize(context);
    }

これを、以下のように改変する。

    void Application_BeginRequest(object source, EventArgs e)
    {
        HttpApplication app = (HttpApplication)source;
        HttpContext context = app.Context;
        //追加: リバースプロキシを使ってるので、絶対パスを手で指定しないといけない
        context.Items["absoluteurl"] = new Uri("http://blog.ebuta.net/");
        // Attempt to perform first request initialization
        FirstRequestInitialization.Initialize(context);
    }

なお、URLは環境に合わせて書き換えること。

こうすることで、リンクに正しいURLが出力されるようになった。

実際には、Extentionとして実装するのがスマートなのかも知れないが、いまのところまだ仕様がよく分かっていないので別の機会に試して見ようと思う。

 

<追記>

AbsoluteWebRootを使用していない箇所があるようだ。

post.aspx.csの以下の部分。

                    if (BlogSettings.Instance.EnablePingBackReceive)
                    {
                        Response.AppendHeader("x-pingback", "http://" + Request.Url.Authority + Utils.RelativeWebRoot + "pingback.axd");
                    }

これを編集して以下のように改変する。

                    if (BlogSettings.Instance.EnablePingBackReceive)
                    {
                        Response.AppendHeader("x-pingback", Utils.AbsoluteWebRoot + "pingback.axd");
                    }