2011-12-20 31 views
5

Tôi có một điều khiển người dùng web, nó phục vụ một số tính toán dữ liệu có khả năng chuyên sâu và tôi muốn nó được lưu trữ đầu ra để mỗi lần xem trang không tính toán lại dữ liệu . Nó nằm trên các trang được xem rất thường xuyên vì vậy nó khá quan trọng tôi làm cho nó hoạt động đúng!ASP.net Làm thế nào để tạo ra bộ nhớ cache một webusercontrol kiểm soát tài sản công cộng

Đối với bối cảnh, nó được sử dụng trên trò của chúng tôi: http://www.scirra.com/arcade/action/93/8-bits-runner

Bấm vào số liệu thống kê, dữ liệu cho các đồ thị và số liệu thống kê được tạo ra từ webusercontrol này.

Sự bắt đầu của sự kiểm soát như sau:

public partial class Controls_Arcade_Data_ArcadeChartData : System.Web.UI.UserControl 
{ 
    public int GameID { get; set; } 
    public Arcade.ChartDataType.ChartType Type { get; set; } 

    protected void Page_Load(object sender, EventArgs e) 
    { 

Bây giờ những khó khăn tôi đang gặp là output cache cần phải phụ thuộc vào cả GamID và Loại biểu đồ.

Điều khiển này được tái sử dụng với nhiều kết hợp khác nhau của GameID và các loại, tôi cần nó để tạo bộ nhớ cache cho từng loại nhưng tôi đang cố gắng tìm hiểu cách thực hiện.

Ví dụ, một trò chơi điện tử có thể vượt qua trong GameID = 93Type = GraphData, khác có thể GameID = 41Type = TotalPlaysData và khác có thể GameID = 93 nhưng Type = TotalPlaysData. Tất cả những dữ liệu này sẽ trả về các dữ liệu khác nhau và có các bộ đệm đầu ra khác nhau.

Việc kiểm soát được sử dụng trên trang trò chơi loại như thế này (các thông số đang thực sự thiết lập trong codebehind)

<div>Total Plays:</div> 
<div class="count"><Scirra:ArcadeChartData runat="server" GameID="93" Type="TotalPlays" /></div> 
<br /><br /> 
<div>Total Guest Plays:</div> 
<div class="count"><Scirra:ArcadeChartData runat="server" GameID="93" Type="TotalGuestPlays" /></div> 

etc. 

Bất kỳ giúp đánh giá cao! Tôi đã dành một thời gian tìm kiếm trực tuyến và nó vẫn tiếp tục như một thứ tôi cần phải giải quyết nhưng không thể hình dung ra điều này.

Sửa

Edit: Tôi đã thử thêm dòng này để kiểm soát của tôi: <% @ OutputCache Thời gian = "20" VaryByControl = "GameID; Loại" %>

Nhưng nó chỉ ném lỗi Object reference not set to an instance of an object. trên dòng nơi GameID đang được đặt lần đầu tiên trên trang ASPX bằng cách sử dụng điều khiển.

Trả lời

9

Khi điều khiển được truy xuất từ ​​bộ nhớ cache đầu ra, nó không được khởi tạo như một thể hiện mà bạn có thể thao tác; bạn chỉ nhận được đầu ra của Control được tạo ra, chứ không phải bản thân Control. Ví dụ: bạn không thể đặt thuộc tính trên Kiểm soát được lưu trong bộ nhớ cache từ mã phía sau, như bạn đã nói trong câu hỏi của mình. Các thuộc tính khác nhau nên được thiết lập một cách khai báo (sử dụng ExpressionBuilder cũng có thể làm việc, mặc dù tôi chưa thử nó).

Để xem trong mã phía sau cho dù một điều khiển đã được lấy ra từ bộ nhớ cache đầu ra, kiểm tra null:

if (this.YourControlID != null) // true if not from cache 
{ 
    // do stuff 
} 

Ngay cả với báo trước rằng, kiểm soát sản lượng bộ nhớ đệm là một chút kỳ quặc.

Hãy thử điều này:

<%@ OutputCache Duration="20" VaryByControl="GameID;Type" Shared="true" %> 

Đầu ra của kiểm soát được lưu trữ trong bộ nhớ cache đầu ra bằng cách kết hợp nó với một phím nào đó. Với Shared="true", khóa bộ nhớ cache là giá trị của tất cả các thuộc tính được chỉ định cùng với ID của Kiểm soát. Nếu không có Shared="true", khóa bộ nhớ cache cũng bao gồm loại Trang, do đó đầu ra sẽ thay đổi theo Trang - điều này không giống như những gì bạn muốn.

Nếu bạn sử dụng Điều khiển trên nhiều trang, hãy đảm bảo sử dụng cùng một ID trên mỗi trang nếu bạn có thể, vì ID được bao gồm như một phần của khóa cho bộ đệm đầu ra. Nếu bạn không thể hoặc không sử dụng các ID khác nhau, bạn sẽ nhận được một bản sao mới của đầu ra của Kiểm soát trong bộ nhớ cache cho mỗi ID duy nhất. Nếu các điều khiển với các ID khác nhau luôn có giá trị thuộc tính khác nhau, điều đó có thể không phải là một vấn đề.

Là một thay thế cho Chỉ thị OutputCache, bạn có thể đặt một thuộc tính trên tờ khai lớp:

[PartialCaching(20, null, "GameID;Type", null, true)] 
public partial class Controls_Arcade_Data_ArcadeChartData : UserControl 
+0

vì anh ấy muốn sử dụng kiểm soát nhiều lần trong cùng một trang, giải pháp này không hợp lệ. không thể có cùng một ID cho nhiều điều khiển trong cùng một trang. –

+2

Bạn có thể sử dụng các ID khác nhau trên cùng một trang; chỉ cần nhớ rằng ID là một phần của khóa bộ nhớ cache, vì vậy có thể nhận được nhiều bản sao của cùng một đầu ra. Nếu Kiểu luôn được đặt dựa trên vị trí của điều khiển trên trang, như trong câu hỏi, đó có thể không phải là vấn đề. – RickNZ

+0

Điều này dường như hoạt động như tôi muốn! Sẽ kiểm tra nhiều hơn một chút và báo cáo lại. –

3

Bạn cần phải thực hiện các bước sau:

1) Thêm chỉ thị output cache sau để trang:

<%@ OutputCache Duration="21600" VaryByParam="None" VaryByCustom="FullURL" %> 

2) Thêm dòng sau vào global.asax:

public override string GetVaryByCustomString(HttpContext context, string arg) 
    { 
     if (arg.Equals("FullURL", StringComparison.InvariantCultureIgnoreCase) 
     { 
      // Retrieves the page 
      Page oPage = context.Handler as Page; 

      int gameId; 

      // If the GameID is not in the page, you can use the Controls 
      // collection of the page to find the specific usercontrol and 
      // extract the GameID from that. 

      // Otherwise, get the GameID from the page 

      // You could also cast above 
      gameId = (MyGamePage)oPage.GameID; 

      // Generate a unique cache string based on the GameID 
      return "GameID" + gameId.ToString(); 
     } 
     else 
     { 
      return string.Empty; 
     } 
    } 

Bạn có thể nhận thêm thông tin về phương pháp GetVaryByCustomString từ MSDN và cũng xem xét một số tùy chọn bộ nhớ đệm khác here.

+0

Tôi có đúng khi nghĩ rằng điều này sẽ lưu trong 6 giờ dựa trên URL của trang? Các dữ liệu sẽ được trên nhiều URL, tôi chỉ muốn nó vào bộ nhớ cache dựa trên 'GameID'. –

+0

@TomGullen: Thời lượng bằng giây, vì vậy giá trị tôi có trong đó sẽ chỉ tốt trong 10 phút; Tôi đã điều chỉnh giá trị đúng (21600). Cách mà phương thức được thiết kế, nó sẽ lưu vào bộ nhớ cache trên URL đầy đủ, nhưng bạn có thể điều chỉnh hành vi này nếu cần trong phương thức GetVaryByCustomString nếu bạn có các tham số chuỗi truy vấn bổ sung. –

+0

Mặc dù tôi không có thông số truy vấn, tôi có một điều khiển có thuộc tính công khai mà tôi muốn lưu vào bộ nhớ cache. –

2

tạo ra một đối tượng bộ nhớ cache trong mã

HttpRuntime.Cache.Insert("ArcadeChartData" + GameID + Type, <object to cache>, null, System.Web.Caching.Cache.NoAbsoluteExpiration,new TimeSpan(0, 0, secondsToCache),CacheItemPriority.Normal, null); 

trên mục bộ nhớ cache sẽ đủ để công việc của bạn, nhưng nếu bạn thực sự muốn sử dụng bộ nhớ cache đầu ra cũng cố gắng sau mã trong mã phía sau,

Response.AddCacheItemDependency("ArcadeChartData" + GameID + Type); 
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)); 
Response.Cache.SetCacheability(HttpCacheability.Public); 
Response.Cache.SetValidUntilExpires(true); 

Giá trị cài đặt cho bộ nhớ cache đầu ra trang giống như thao tác phương thức SetExpires và SetCacheability thông qua thuộc tính Bộ nhớ cache.

+0

Cảm ơn, tôi có chính xác trong việc nói cả hai bit mã này dành cho điều khiển webuser không? Và sự khác nhau giữa hai người là gì? –

+0

bộ nhớ cache đầu ra là bộ nhớ đệm html kết xuất cuối cùng trong cấp IIS và nó sẽ không cho phép bạn đi đến mã. nhưng nếu bạn sử dụng 'HttpRuntime.Cache' nó sẽ cache đối tượng bạn chỉ định và yêu cầu sẽ nhấn vào trang thực tế nhưng không phải là phép tính trong đối tượng được lưu trữ. nếu bạn thực sự muốn sử dụng bộ nhớ cache đầu ra, bạn có thể sử dụng phụ thuộc đối tượng với đối tượng được lưu trong bộ nhớ cache. –

+0

Tôi chắc chắn muốn sử dụng bộ nhớ cache đầu ra vì tôi không muốn mỗi khách truy cập mới có đối tượng được hiển thị lại, nếu chúng tôi có một trò chơi phổ biến với 10.000 lượt phát trong 1 ngày thì có thể khó thực hiện trên máy chủ. Vì vậy, tôi nghĩ rằng bộ nhớ cache đầu ra là lựa chọn tốt nhất. –

0

Một mẹo đơn giản là đặt tất cả đồ họa vào trang mới nhận GameId và nhập làm thông số chuỗi truy vấn, sử dụng bộ nhớ cache đầu ra ngoài hộp cho tham số truy vấn và đặt khung nội tuyến trong trang của bạn. Ngoài ra, bạn có thể sử dụng bộ nhớ cache của trình duyệt và không bao giờ bị máy chủ truy cập trong một thời gian.

1

Tôi biết rằng giải pháp của tôi có thể trông rất đơn giản và có thể lạ nhưng tôi đã thử nó và nó hoạt động. Bạn chỉ cần thêm dòng này vào UserControl của mình.

<%@ OutputCache Duration="10" VaryByParam="none" %> 

Lưu ý: Tôi chỉ thử nghiệm Khung 4.0. Ngoài ra nếu bao giờ bạn phải thay đổi giá trị của thuộc tính trong UserControl (MyInt, My String trong ví dụ này) làm điều đó trong sự kiện Page_Init.

Dưới đây là tất cả các mã của tôi:

Page:

<%@ Page Title="Home Page" Language="vb" MasterPageFile="~/Site.Master" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="MyWebApp._Default" %> 
<%@ Register Src="~/UserControl/MyUserControl.ascx" TagPrefix="uc" TagName="MyUserControl" %> 

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent"> 
</asp:Content> 

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent"> 
    <uc:MyUserControl ID="uc1" MyInt="1" MyString="Test" runat="server" /> 
    <hr /> 
    <uc:MyUserControl ID="uc2" MyInt="3" MyString="Test" runat="server" /> 
    <hr />  
    <uc:MyUserControl ID="uc3" MyInt="1" MyString="Testing" runat="server" /> 
</asp:Content> 

Bản quyền thuộc về:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="MyUserControl.ascx.vb" Inherits="MyWebApp.MyUserControl" %> 
<%@ OutputCache Duration="10" VaryByParam="none" %> 

<div style="background-color:Red;"> 
    Test<br /> 
    <asp:Label ID="lblTime" ForeColor="White" runat="server" /> 
</div> 

User Control Code:

Public Class MyUserControl 
    Inherits System.Web.UI.UserControl 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
     Debug.Write("Page_Load of {0}", Me.ID) 
     Dim oStrBldr As New StringBuilder() 
     For i As Integer = 1 To Me.MyInt 
      oStrBldr.AppendFormat("{0}: {1} - {2} at {3}<br />{4}", Me.ID, i, Me.MyString, Date.Now.ToLongTimeString(), System.Environment.NewLine) 
     Next 
     Me.lblTime.Text = oStrBldr.ToString() 
    End Sub 


    Public Property MyInt As Integer 
    Public Property MyString As String 

End Class 

Hãy giữ cho tôi được đăng, tôi có các giải pháp khác nếu bạn mong ước nhưng chúng phức tạp hơn. Tôi cũng có thể đăng bài bằng C#

+0

Điều này không có tác dụng, khi tôi thử và đặt' GameID = TheGame.ID; 'trong trang ASPX giữ điều khiển nó ném một tham chiếu 'đối tượng không được thiết lập để một thể hiện của một object.' lỗi khi cố gắng để tải bộ nhớ cache –

+0

Điều này thực sự hoạt động. Có vẻ như asp.net đang sử dụng các thuộc tính được định nghĩa trong thẻ đánh dấu (trong trường hợp này Richard

0

Ok, cũng lý do tại sao điều này rất khó để làm OutputCache làm việc trong trường hợp này là bởi vì nó không được thiết kế để sử dụng với Thuộc tính của, tuy nhiên nó hoạt động rất tốt với thông số QueryString. Vì vậy, giải pháp tiếp theo của tôi không phải là giải pháp chuyên nghiệp nhất và có lẽ không phải là tốt nhất, nhưng nó chắc chắn là nhanh nhất và giải pháp yêu cầu ít thay đổi mã hơn.

Kể từ khi nó hoạt động tốt nhất QueryString, tôi khuyên bạn nên đặt bạn UserControl trong một trang trống, và xoay về bao giờ bạn muốn sử dụng bạn UserControl thực hiện một iframe liên kết đến trang của bạn với UserControl với QueryString.

Trong trường hợp bạn muốn sử dụng UserControl của bạn:

<iframe src="/MyArcadeChartData.aspx?GameID=93&Type=TotalPlays"></iframe> 

đánh dấu đầy đủ trang, MyArcadeChartData.aspx

<%@ Page ... %> 
<%@ OutputCache Duration="20" VaryByParam="GameID;Type" %> 
<Scirra:ArcadeChartData ID="MyUserControlID" runat="server /> 

Full mã trang, MyArcadeChartData.aspx.cs

protected void Page_Load(object sender, EventArgs e) 
{ 
    //TODO: Put validation here 
    MyUserControlID.GameID = (int)Request.QueryString["GameID"]; 
    MyUserControlID.Type = (YourEnum)Request.QueryString["Type"]; 
} 

Hãy không phải là giá trị trong QueryString có thể được nhìn thấy bởi người sử dụng, xin vui lòng không đưa dữ liệu nhạy cảm.

Ngoài ra, tôi biết rằng đây không phải là giải pháp chuyên nghiệp nhất, nhưng nó là giải pháp dễ thực hiện nhất, từ những gì tôi biết.

Kính trọng và ngày nghỉ vui vẻ

+0

Tôi chỉ chú ý hơn ivowiblo đăng câu trả lời tương tự như tôi, tôi chỉ đơn giản là putted thêm lời giải thích và chi tiết. – plauriola

0

Nếu tôi hiểu đúng, bộ nhớ đệm không hoạt động một cách chính xác vì cách bạn có các thuộc tính cung cấp các giá trị để kiểm soát, mà có lẽ đã làm, một phần, với tính toán đang được thực hiện.

Bạn có thể tạo HttpHandlerFactory để nhận yêu cầu, tính toán của bạn nếu chúng không có trong bộ đệm (chèn vào bộ đệm sau), xử lý hết hạn giá trị và sau đó chuyển yêu cầu lên trang. Nó sẽ không được kiểm soát cụ thể cả. Bằng cách đó bạn có thể sử dụng các giá trị được tính toán này trong bất kỳ điều khiển hoặc trang nào và sẽ không phải triển khai các chính sách lưu vào bộ nhớ đệm mà lo lắng về các phép tính của riêng chúng.

0

Nếu đây không phải là dữ liệu chuyên sâu, bạn có xem xét lưu trữ dữ liệu trong Phiên làm việc như được đặt vào bộ nhớ đệm không? Chỉ cần một ý nghĩ ...

Arcade.ChartDataType.ChartType Type; 
string GameKey = GameId + Type.toString(); 
storedData = callCalculation(GameId,Type); 
Session[GameKey] = storedData; 

Tôi nhận ra điều này không có trong bộ nhớ cache, tôi chỉ đang cố gắng xây dựng.

Các vấn đề liên quan