2011-01-18 31 views
17

Tôi đang cố gắng sử dụng hồ sơ bộ nhớ cache để lưu vào bộ nhớ cache các hành động con trong ứng dụng mvc của tôi, nhưng tôi nhận được ngoại lệ: Thời lượng phải là số dương.Caching ChildActions sử dụng cấu hình bộ nhớ cache sẽ không hoạt động?

web.config của tôi trông như thế này:

<caching> 
     <outputCache enableOutputCache="true" /> 
     <outputCacheSettings> 
     <outputCacheProfiles> 
      <add name="TopCategories" duration="3600" enabled="true" varyByParam="none" /> 
     </outputCacheProfiles> 
     </outputCacheSettings> 
</caching> 

Và hành động con tôi một cái gì đó như thế này:

[ChildActionOnly] 
[OutputCache(CacheProfile = "TopCategories")] 
//[OutputCache(Duration = 60)] 
public PartialViewResult TopCategories() 
{ 
    //... 
    return PartialView(); 
} 

Bên trong một cái nhìn tôi chỉ cần gọi @Html.RenderAction("TopCategories", "Category")

Nhưng tôi nhận được một lỗi : Chi tiết ngoại lệ: System.InvalidOperationException: Thời lượng phải là số dương.

Nếu tôi không sử dụng hồ sơ bộ nhớ cache, nó hoạt động. Có một ý tưởng là vấn đề gì?

Trả lời

17

tôi đã làm một số đào trên related question và nhìn vào MVC 3 nguồn, họ chắc chắn không hỗ trợ thuộc tính bất kỳ khác hơn Thời gianVaryByParam. Lỗi chính với việc triển khai hiện tại của chúng là nếu bạn không cung cấp một trong hai điều này, bạn sẽ nhận được một ngoại lệ yêu cầu bạn cung cấp, thay vì ngoại lệ nói rằng những gì bạn đã cố gắng sử dụng không được hỗ trợ. Vấn đề lớn khác là họ sẽ cache ngay cả khi bạn tắt bộ nhớ đệm trong web.config, điều này có vẻ thực sự không đáng tin cậy và không đúng.

Vấn đề lớn nhất mà tôi gặp phải là chúng đang sử dụng cùng thuộc tính hoạt động ở cả chế độ xem và lượt xem một phần, nhưng thực tế nó có thể là 2 thuộc tính khác nhau vì chế độ xem một phần quá hạn chế và hoạt động rất nhiều khác nhau, ít nhất là trong thực hiện hiện tại.

+0

Cám ơn câu trả lời của bạn :) – frennky

+2

Dưới đây là một bài viết tốt đẹp mà giải thích vấn đề này: http://www.dotnetcurry.com/ShowArticle.aspx?ID=665 – frennky

+0

tôi cố định này và gửi một yêu cầu kéo ngày hôm nay: http://aspnetwebstack.codeplex.com/SourceControl/network/forks/ssmith/OutputCacheAttributeBugfix/contribution/4100 cũng như viết một bài viết về cách tự khắc phục sự cố này (thông qua yêu cầu kéo) ngoài việc chỉ bình luận về nó trên SO: http://ardalis.com/how-to-contribute-to-aspnet-yourself – ssmith

2

Đây là một cách đơn giản nếu:

  • mục tiêu cơ bản của bạn là để có thể vô hiệu hóa bộ nhớ cache trong gỡ lỗikích hoạt nó trong việc triển khai
  • chính sách bộ nhớ đệm Bạn không có phức tạp (điều đó có nghĩa là bạn thực sự cần phải tôn trọng cài đặt bộ nhớ đệm của Web.config)
  • Bạn không có hệ thống triển khai phức tạp dựa trên cú pháp lưu trong bộ nhớ cache của Web.config
  • Lý tưởng nếu bạn đang sử dụng XDT web transformations đã
  • Bạn chỉ cho rằng nó đã hoạt động và khó chịu và không cần sửa chữa nhanh!

Tất cả những gì tôi đã tạo được tạo thuộc tính mới 'DonutCache'.

[DonutCache] 
public ActionResult HomePageBody(string viewName) 
{ 
    var model = new FG2HomeModel(); 

    return View(viewName, model); 
} 

Tôi lưu trữ cài đặt bộ nhớ đệm trong Web.config (dưới tên tùy chỉnh mới - để tránh nhầm lẫn).

<appSettings> 
    <add key="DonutCachingDuration" value="5"/> <!-- debug setting --> 
</appSettings> 

Tôi đã tạo phương thức trợ giúp đơn giản để lấy giá trị.

public static class Config { 
    public static int DonutCachingDuration 
    { 
     get 
     { 
      return int.Parse(ConfigurationManager.AppSettings["DonutCachingDuration"]); 
     } 
    } 
} 

Đáng tiếc là bạn chỉ có thể khởi tạo một [Attribute] với một hằng số, vì vậy bạn cần phải khởi tạo các thuộc tính trong constructor của nó (bạn không thể chỉ nói [Attribute(Config.DonutCachingDuration)] không may).

Lưu ý: Điều này không ngăn bạn đặt 'varyByParam' trong khai báo [DonutCache] - hiện là thuộc tính duy nhất có thể sử dụng để lưu vào bộ nhớ cache của các phương thức Hành động.

class DonutCacheAttribute : OutputCacheAttribute 
{ 
    public DonutCacheAttribute() 
    { 
     // get cache duration from web.config 
     Duration = Config.DonutCachingDuration; 
    } 
} 

Chỉ cần sử dụng chuyển đổi web XDT và bạn đã sẵn sàng triển khai với giá trị dài hơn.

<add key="DonutCachingDuration" value="120" 
     xdt:Locator="Match(key)" xdt:Transform="Replace"/> 

Mẹo: Có thể bạn sẽ muốn dính vào một @DateTime.Now.ToString() theo quan điểm từng phần của bạn để chắc chắn rằng các thiết lập bộ nhớ cache đã được tôn trọng.

-1

Trong một số trường hợp, có thể thích hợp để chỉ tạo phương thức hành động thứ hai, với tính năng bộ nhớ đệm bị tắt được gọi bằng hành động chính của bạn.

/// Use this for normal HTTP requests which need to be cached 
    [OutputCache(CacheProfile = "Script")] 
    public ContentResult Foo(string id) 
    { 
     return _Foo(id); 
    } 

    /// Use this for Html.Action 
    public ContentResult _Foo(string id) 
    { 
     return View(); 
    } 

Khi bạn cần Html.Action bạn chỉ cần gọi _Foo thay vì Foo.

@Html.Action("_Foo", "Bar").ToString(); 

Sau đó, bạn có thể dựa vào trang gốc để lưu bộ nhớ đệm. Nếu điều này không phù hợp (vì bạn không muốn lưu toàn bộ trang) - bạn có thể sử dụng 'DonutCacheAttribute' từ câu trả lời khác của tôi.

+0

Điều này không cho phép sử dụng [ChildActionOnly], vì vậy nó không phải là một câu trả lời – YEH

17

tôi xung quanh vấn đề bằng cách tạo ra một thuộc tính tùy chỉnh OutputCache, điều đó bằng tay tải Duration, VarByCustomVarByParam từ hồ sơ cá nhân:

public class ChildActionOutputCacheAttribute : OutputCacheAttribute 
{ 
    public ChildActionOutputCacheAttribute(string cacheProfile) 
    { 
     var settings = (OutputCacheSettingsSection)WebConfigurationManager.GetSection("system.web/caching/outputCacheSettings"); 
     var profile = settings.OutputCacheProfiles[cacheProfile]; 
     Duration = profile.Duration; 
     VaryByParam = profile.VaryByParam; 
     VaryByCustom = profile.VaryByCustom; 
    } 
} 

Ưu điểm của phương pháp này là bạn có thể vẫn giữ tất cả các bạn hồ sơ chỉ trong một vị trí trong web.config.

+0

Khi tôi đăng câu hỏi, tôi nghĩ rằng tôi đã làm điều gì đó sai và không nghi ngờ đó là một vấn đề khung. Cuối cùng tôi đã đi với một giải pháp tương tự. – frennky

+0

Yup, điều tương tự đã xảy ra với tôi. Và kể từ khi tôi đã có thể làm việc ra một giải pháp tương đối đơn giản, quyết định thêm id vào chủ đề cũ này trong trường hợp nó giúp người khác. –

+3

Hoạt động tuyệt vời - tôi phải ghi đè lên 'OnActionExecuting' và gọi' base.OnActionExecuting' chỉ khi cấu hình cache được kích hoạt trong web.config. Nếu không, "Thời gian" sợ hãi sẽ xuất hiện lại khi đặt 'enabled =" false "'. – marapet

-1

Điều đó phù hợp với tôi.

public class ChildActionOutputCacheAttribute : OutputCacheAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if (filterContext.IsChildAction && !string.IsNullOrWhiteSpace(CacheProfile)) 
     { 
      lock (this.GetType()) 
      { 
       if (!string.IsNullOrWhiteSpace(CacheProfile)) 
       { 
        // OutputCacheAttribute for child actions only supports 
        // Duration, VaryByCustom, and VaryByParam values. 
        var outputCache = (OutputCacheSettingsSection)WebConfigurationManager.GetSection("system.web/caching/outputCacheSettings"); 
        var profile = outputCache.OutputCacheProfiles[CacheProfile]; 
        if (profile.Enabled) 
        { 
         Duration = profile.Duration > 0 ? profile.Duration : Duration; 
         VaryByCustom = string.IsNullOrWhiteSpace(profile.VaryByCustom) 
          ? VaryByCustom : profile.VaryByCustom; 
         VaryByParam = string.IsNullOrWhiteSpace(profile.VaryByParam) 
          ? VaryByParam : profile.VaryByParam; 
        } 
        CacheProfile = null; 
       } 
      } 
     } 
     base.OnActionExecuting(filterContext); 
    } 
} 
Các vấn đề liên quan