12

[ CompressFilter ]をドーナツキャッシングで動作させようとしていますが、問題が発生しています。

ドーナツだけでなく、ページ全体がキャッシュされます。CompressFilter私が使用しているソースは以下のとおりです。特定のActionResultサブクラスのキャッシュを回避するために結果のタイプにアクセスする必要があったため、これを元のソースOnResultExecutedから代わりに使用するように変更しました。OnActionExecuting()

実際のMVCv1ソースコードをOutputCacheAttribute見ると、それも使用しているように見えOnResultExecuted()ますが、事実が直接競合を引き起こしているとは思いません。

置換キャッシングがどのように機能するかについては、なぜそのように動作するのかを理解するのに十分な知識がありません。これは、いかなる種類の破損した表示にもならないということは注目に値することだと思います。ドーナツがないように振る舞います!

キャッシングを処理するには、ある種のIIの「プラグイン」を使用する必要があるように見えます。これは、実際には避けたかったのですが、ドーナツキャッシングも必要なようです。

私は実際、なぜそれがこの効果をもたらすのかを知りたいと思っていますが、可能であれば解決策も素晴らしいでしょう。

public class CompressFilter : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        // dont encode images!
        if (filterContext.Result is ImageResult)
        {
            return;
        }

        string acceptEncoding = request.Headers["Accept-Encoding"];

        if (string.IsNullOrEmpty(acceptEncoding)) return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;

        if (acceptEncoding.Contains("GZIP"))
        {
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}
4

2 に答える 2

10

これは、CompressFilter クラスの不適切な実装です。

これを読んでください: C# での優先受け入れエンコーディングの検索

上記の記事に基づいて、AcceptEncoding に従う独自のコードを作成しました::

public class CompressFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        string[] supported = new string[] { "gzip", "deflate" };

        IEnumerable<string> preferredOrder = new AcceptList(request.Headers["Accept-Encoding"], supported);

        string preferred = preferredOrder.FirstOrDefault();

        HttpResponseBase response = filterContext.HttpContext.Response;

        switch (preferred)
        {
            case "gzip":
                response.AppendHeader("Content-Encoding", "gzip");
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                break;

            case "deflate":
                response.AppendHeader("Content-Encoding", "deflate");
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                break;

            case "identity":
            default:
                break;
        }
    }
}

public class AcceptList : IEnumerable<string>
{
    Regex parser = new Regex(@"(?<name>[^;,\r\n]+)(?:;q=(?<value>[\d.]+))?", RegexOptions.Compiled);

    IEnumerable<string> encodings;

    public AcceptList(string acceptHeaderValue, IEnumerable<string> supportedEncodings)
    {
        List<KeyValuePair<string, float>> accepts = new List<KeyValuePair<string, float>>();

        if (!string.IsNullOrEmpty(acceptHeaderValue))
        {
            MatchCollection matches = parser.Matches(acceptHeaderValue);

            var values = from Match v in matches
                         where v.Success
                         select new
                         {
                             Name = v.Groups["name"].Value,
                             Value = v.Groups["value"].Value
                         };

            foreach (var value in values)
            {
                if (value.Name == "*")
                {
                    foreach (string encoding in supportedEncodings)
                    {
                        if (!accepts.Where(a => a.Key.ToUpperInvariant() == encoding.ToUpperInvariant()).Any())
                        {
                            accepts.Add(new KeyValuePair<string, float>(encoding, 1.0f));
                        }
                    }

                    continue;
                }

                float desired = 1.0f;
                if (!string.IsNullOrEmpty(value.Value))
                {
                    float.TryParse(value.Value, out desired);
                }

                if (desired == 0.0f)
                {
                    continue;
                }

                accepts.Add(new KeyValuePair<string, float>(value.Name, desired));
            }
        }

        this.encodings = from a in accepts
                         where supportedEncodings.Where(se => se.ToUpperInvariant() == a.Key.ToUpperInvariant()).Any() || a.Key.ToUpperInvariant() == "IDENTITY"
                         orderby a.Value descending
                         select a.Key;
    }

    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        return this.encodings.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)this.encodings).GetEnumerator();
    }
}
于 2009-10-13T16:27:25.590 に答える
2

OnResultExecutingメソッドをオーバーライドします。これは、ActionResultをレンダリングする前に呼び出されます。クライアントが圧縮を受け入れるかどうかを確認する前に、レンダリングしようとしている結果のタイプを確認します。それがViewResultでない場合、私はいかなる種類の圧縮も適用しません。

これを機能させるには、アクションでView()またはPartialView()を明示的に呼び出す必要があります。

CompressOutputAttrtibuteは次のようになります。

public class CompressOutputAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext) 
    {
        var result = filterContext.Result;
        if (!(result is ViewResult))
            return;

        HttpRequestBase request = filterContext.HttpContext.Request;
        string acceptEncoding = request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(acceptEncoding))
            return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;
        if (acceptEncoding.Contains("GZIP"))
        {        
            // we want to use gzip 1st
            response.AppendHeader("Content-encoding", "gzip");
            //Add DeflateStream to the pipeline in order to compress response on the fly 
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            //If client accepts deflate, we'll always return compressed content 
            response.AppendHeader("Content-encoding", "deflate");
            //Add DeflateStream to the pipeline in order to compress response on the fly 
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}

コントローラの内部:

[CompressOutput]
public class ArticleController : Controller

    public PartialViewResult MostPopular()
    {
        var viewModel = ArticleMostPopularViewModel();
        viewModel.Articles = CmsService.GetMostPopularArticles();
        return PartialView(viewModel);
    }

    public ViewResult Show(int id)
    {
        var viewModel = ArticleShowViewModel();
        viewModel.Article = CmsService.GetArticle(id);
        return View(viewModel);
    }
}
于 2009-06-12T19:58:22.943 に答える