1

私はいくつかのレガシー Web サイトを持っており、それぞれに多数の静的 HTML ページがあります。IIS モジュールを使用して、生成されたページ コンテンツをキャプチャし、追加の HTML スニペットを追加して新しいヘッダーとフッターを作成したいと考えています (これはデコレーター パターンと呼ばれます)。これが私がモジュール用に持っているコードです。奇妙なことに、多くのテストで、モジュールが 2 回呼び出されていることに気付きました。ページがロードされ、各呼び出しがページのコンテンツの一部をモジュールに渡すとき (最初の呼び出しはページの上部を渡し、2 回目はページの残りの部分を渡します)。モジュールが 2 回呼び出されることがわかっている理由は、静的変数を使用して呼び出しの数を取得し、それを新しいヘッダーとフッターに表示したためです (2 つの数値は異なり、フッター番号は常にヘッダー番号よりも 1 大きくなります)。また、それを証明するために、ページ コンテンツを 2 つの異なるファイルにエクスポートすることもできました。

namespace MyProject
{
    public class MyModule : IHttpModule
    {
        public void Dispose()
        {
        }

        public void Init(HttpApplication application)
        {
            application.ReleaseRequestState += new EventHandler(this.My_Wrapper);
        }

        public String ModuleName
        {
            get { return "MyProject"; }
        }

        public void My_Wrapper(Object source, EventArgs e)
        {
            HttpApplication app = (HttpApplication)source;
            HttpContext context = app.Context;
            HttpRequest request = context.Request;
            string requestPath = request.Path.ToString();

            //I have guarding code here so that the following code only applies to 
            //web requests that has ".html" in the end.

            HttpContext.Current.Response.Filter = new WrapperFilter(HttpContext.Current.Response.Filter);
        }
    }

    public class WrapperFilter : MemoryStream
    {
        private static Regex startOfBody = new Regex("(?i)<body(([^>])*)>", RegexOptions.Compiled | RegexOptions.Multiline);
        private static Regex endOfBody = new Regex("(?i)</body>", RegexOptions.Compiled | RegexOptions.Multiline);

        private Stream outputStream = null;

        private static int index = 0;

        public WrapperFilter(Stream output)
        {
            outputStream = output;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            string contentInBuffer = UTF8Encoding.UTF8.GetString(buffer);
            string page = new StringBuilder(contentInBuffer).ToString();
            byte[] outputBuffer = null;
            Match matchStartOfBody = null;
            Match matchEndOfBody = null;

            index++;

            matchStartOfBody = startOfBody.Match(page);
            string header = "html snippets for header: " + index;
            page = startOfBody.Replace(page, "<body " + matchStartOfBody.Groups[1] + ">" + header);

            matchEndOfBody = endOfBody.Match(page); 
            string footer = "html snippets for footer: " + index;
            page = endOfBody.Replace(page, footer + "</body>");

            outputBuffer = UTF8Encoding.UTF8.GetBytes(page);
            outputStream.Write(outputBuffer, 0, outputBuffer.Length);
        }
    }
}

質問:

  1. モジュールが 2 回読み込まれる理由は、ページ コンテンツが大きすぎるか、キャッシュを増やす必要があるためですか? もしそうなら、どのように?

  2. 技術的に、私のアプローチは機能しますか? HTML ページを装飾することができましたが、2 つの呼び出しプロセスが原因で、いくつかの高度な状況を処理できません。

  3. ブラウザ ページに画像を表示する必要があり、画像の要求が IIS モジュールを通過する場合

アップデート

usr からの貴重な情報に基づくと、「奇妙な」動作は IIS の通常の動作にすぎません。彼/彼女の提案のために、クラス変数を追加しました:

private byte[] allContent = new byte[0];

および次の更新されたメソッド:

    public override void Write(byte[] buffer, int offset, int count)
    {
        //new bigger array
        byte[] newArr = new byte[allContent.Length + buffer.Length];
        //copy old content
        System.Array.Copy(allContent, newArr, allContent.Length);
        //append new content
        System.Array.Copy(buffer, 0, newArr, allContent.Length, buffer.Length);
        //reset current total content
        allContent = newArr;
    }

以前の Write メソッドからすべてのコードをコピーした新しいメソッドを追加します。

    protected override void Dispose(bool disposing)
    {
    //code copied from my earlier code, with "buffer" changed to "allContent".
    }

今、すべてが動作します!ありがとうございます!

4

1 に答える 1

1

OK, I should have solved this earlier. I admit I did not read every sentence of the question. I should have grown suspicious of the measurement. Turns out the measurement is broken.

Thanks for asking the question about whether the page size matters. I did tests again. It does. For small pages, I see the same number in header and footer. For large pages, I see 3 and 4 or something like that.

Then:

    public override void Write(byte[] buffer, int offset, int count)
    {
        //...

        index++;

Write might be called an arbitrary number of times. This is a Stream implementation. Anyone can call Stream.Write as often as he wants to. You would expect that with any Stream.

The index can be incremented many times per page. The counting code is broken, the rest works.

Also, the UTF-8 processing is broken because you can't split UTF-8 encoded data at arbitrary boundaries.

于 2016-03-22T18:25:36.593 に答える