2009-05-15 55 views
11

我試圖獲得[CompressFilter]甜甜圈緩存和運行問題。我可以在ASP.NET MVC中使用[CompressFilter]而不破壞甜甜圈緩存

發生的是整個頁面被緩存,而不僅僅是甜甜圈。下面是我使用的CompressFilter的來源。我將其從original source更改爲使用OnResultExecuted而不是OnActionExecuting(),因爲我需要訪問結果的類型以避免緩存某些ActionResult子類。

看看OutputCacheAttribute的實際MVC v1源代碼,它看起來也是使用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); 
     } 
    } 
} 
+0

+1:

請仔細閱讀本。 –

+0

@jordan謝謝!我只是希望它沒有花費我一個小時才能弄清楚這個愚蠢的[CompressFilter]是什麼衝突。我正在檢查一切可能的原因,因爲甜甜圈緩存失敗,真的希望這不是問題 –

+0

+1指向我這個有用的過濾器。謝謝! – jao

回答

9

這是一個不好的實現CompressFilter類的。爲說明您已通過源代碼看起來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

謝謝。唯一的區別是接受編碼嗎?我沒有時間現在比較他們。 thx再 –

+0

是的,非常。 –

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

+1使用OnResultExecuting。我發現在OnActionExecuting中應用壓縮會導致出現問題,因爲Content-Encoding標頭被清除而不是過濾流。 –