2012-03-27 6 views
3

Мне нужно кэшировать созданное содержимое пользовательских WebControls. Поскольку накопление иерархии сбора управления очень дорого, простое кэширование результатов базы данных недостаточно. Кэширование всей страницы невозможно, потому что на странице есть другие динамические части.Частичное кэширование пользовательских WebControls

Мой вопрос: существует ли наилучшая практика для этой проблемы? Я нашел много решений, кэширующих целые страницы или статические UserControls, но ничего не подходит для меня. Я закончил свое решение, но я очень сомневаюсь, что это приемлемый подход.

Обычай WebControl, который должен быть в кэше может выглядеть следующим образом:

public class ReportControl : WebControl 
{ 
    public string ReportViewModel { get; set; } 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     // Fake expensive control hierarchy build up 
     System.Threading.Thread.Sleep(10000); 

     this.Controls.Add(new LiteralControl(ReportViewModel)); 
    } 
} 

страница ASPX, которая включает в себя контроль контента (ы) может выглядеть следующим образом:

public partial class Default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     // Fake authenticated UserID 
     int userID = 1; 

     // Parse ReportID 
     int reportID = int.Parse(Request.QueryString["ReportID"]); 

     // Validate if current user is allowed to view report 
     if (!UserCanAccessReport(userID, reportID)) 
     { 
      form1.Controls.Add(new LiteralControl("You're not allowed to view this report.")); 
      return; 
     } 

     // Get ReportContent from Repository 
     string reportContent = GetReport(reportID); 

     // This controls needs to be cached 
     form1.Controls.Add(new ReportControl() { ReportViewModel = reportContent }); 
    } 

    private bool UserCanAccessReport(int userID, int reportID) 
    { 
     return true; 
    } 

    protected string GetReport(int reportID) 
    { 
     return "This is Report #" + reportID; 
    } 
} 

я в конечном итоге написание два элемента управления оболочкой, один для захвата сгенерированного html и второй для кэширования содержимого. Довольно много кода для простой функции кеширования (см. ниже).

управление оберткой для захвата вывода перезаписывает функцию визуализации и выглядит следующим образом:

public class CaptureOutputControlWrapper : Control 
{ 
    public event EventHandler OutputGenerated = (sender, e) => { }; 

    public string CapturedOutput { get; set; } 

    public Control ControlToWrap { get; set; } 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     this.Controls.Add(ControlToWrap); 
    } 

    protected override void Render(HtmlTextWriter writer) 
    { 
     StringWriter stringWriter = new StringWriter(); 
     HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter); 

     base.RenderChildren(htmlTextWriter); 

     CapturedOutput = stringWriter.ToString(); 

     OutputGenerated(this, EventArgs.Empty); 

     writer.Write(CapturedOutput); 
    } 
} 

управление оберткой кэшировать этот сгенерированный вывод выглядит следующим образом:

public class CachingControlWrapper : WebControl 
{ 
    public CreateControlDelegate CreateControl; 

    public string CachingKey { get; set; } 

    public delegate Control CreateControlDelegate(); 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     string content = HttpRuntime.Cache.Get(CachingKey) as string; 

     if (content != null) 
     { 
      // Content is cached, display 
      this.Controls.Add(new LiteralControl(content)); 
     } 
     else 
     { 
      // Content is not cached, create specified content control and store output in cache 
      CaptureOutputControlWrapper wrapper = new CaptureOutputControlWrapper(); 
      wrapper.ControlToWrap = CreateControl(); 
      wrapper.OutputGenerated += new EventHandler(WrapperOutputGenerated); 

      this.Controls.Add(wrapper); 
     } 
    } 

    protected void WrapperOutputGenerated(object sender, EventArgs e) 
    { 
     CaptureOutputControlWrapper wrapper = (CaptureOutputControlWrapper)sender; 

     HttpRuntime.Cache.Insert(CachingKey, wrapper.CapturedOutput); 
    } 
} 

В моей странице ASPX i с заменой

// This controls needs to be cached 
form1.Controls.Add(new ReportControl() { ReportViewModel = reportContent }); 

с

CachingControlWrapper cachingControlWrapper = new CachingControlWrapper(); 
// CachingKey - Each Report must be cached independently 
cachingControlWrapper.CachingKey = "ReportControl_" + reportID; 
// Create Control Delegate - Control to cache, generated only if control does not exist in cache 
cachingControlWrapper.CreateControl =() => { return new ReportControl() { ReportViewModel = reportContent }; }; 

form1.Controls.Add(cachingControlWrapper); 
+0

Set Page directive. '<% @ OutputCache Duration =" 30000 "VaryByParam =" ReportID "%>' в соответствии с идентификатором reportID или '<% @ OutputCache Duration =" 30000 "VaryByParam =" * "%>' для всех параметров строки запроса – Pankaj

+0

Я не могу кешировать всю страницу, как написано выше. – Dresel

ответ

1

Похоже, хорошая идея, возможно, вам следует обратить внимание на:

  • в ClientIDMode из дочерних элементов управления из пользовательского элемента управления, чтобы предотвратить конфликты, если эти элементы управления будут отображаться в другом контексте
  • LiteralMode вашего литерал: это должно быть Сквозной
  • режим истечения вашего кэшированного элемента (absoluteExpiration/slidingExpiration)
  • отключить ViewState вашего CustomControl

В последнее время я склонен к тому, что у меня есть другой подход: элементы управления оболочкой содержат только javascript, который выполняет запрос AJAX GET на странице, содержащей только мой пользовательский элемент управления. Кэширование выполняется на стороне клиента через HTTP-заголовки и серверы через директиву OutputCache (если HTTPS, контент должен быть общедоступным)

+0

Хорошие замечания - я буду учитывать их. Итак, вы делаете одну страницу для каждого элемента управления кешем - а содержимое страницы вызывается клиентом через JS? – Dresel

+0

Да, используется в правильном контексте, он помогает обмениваться элементами управления (такими как элементы управления навигацией) между приложениями, серверами и сторонними сайтами. Это уменьшает пропускную способность полосы пропускания и сервера. – jbl

+0

Звучит разумно для ваших требований. Кажется немного косвенным, чтобы принять для моей конкретной ситуации. Мне пришлось бы делать вызовы serveride и страницу с кешем управления, недоступным непосредственно клиенту. Если мой UserCanAccessReport имеет значение true, я бы сделал вызов и мог сделать LiteralControl с возвращенным контентом. Тем не менее, спасибо за ваш вклад. – Dresel

Смежные вопросы