2009-05-15 7 views
11

[CompressFilter]は、ドーナツキャッシングと問題に取り組もうとしています。ASP.NET MVCで[CompressFilter]をドーナツキャッシングを破ることなく使用できますか

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

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

私は、代替キャッシュがどのように動作しているのかを理解するためにどのように機能するのか十分に分かりません。私は、これが何らかの種類の壊れたディスプレイで終わるわけではないと言えることは注目に値すると思います。ドーナツがないように振る舞います!

キャッシングを処理するには、ある種のIIsプラグインを使用する必要があるように見えますが、これは私が本当にやりたいのは避けたかったのですが、ドーナツキャッシングも必要です。

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

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); 
     } 
    } 
} 
+0

1を使用すると、ソースコードを見ていることを知らせるために。 –

+0

@jordanありがとう!私は愚かな[CompressFilter]が矛盾していたものだったことを理解するのに1時間ほどかかりませんでした。私は、ドーナツキャッシングが失敗した原因として可能なものをすべてチェックしていましたが、これは問題ではなかったと本当に願っています。 –

+0

+1この役に立つフィルタを私に指摘してください。ありがとう! – jao

答えて

9

を。

これをお読みください:Finding Preferred Accept Encoding in 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(); 
    } 
} 
+0

唯一のdifferneceを受け入れるのですか?私は今はそれらを比較する時間がありません。もう一度 –

+0

ええ、かなり。 –

2

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

これを実行するには、アクションでView()またはPartialView()を明示的に呼び出す必要があります。コントローラ内部

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); 
     } 
    } 
} 

はここCompressOutputAttrtibuteは次のようになりますCompressFilterクラスの悪い実装です

[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); 
    } 
} 
+0

+1は、OnResultExecutingを使用しています。 OnActionExecutingで圧縮を適用すると、Content-Encodingヘッダーがクリアされますが、ストリームはフィルターされないためにエラーが発生したときに問題が発生することがわかりました。ありがとう。 –

関連する問題