Saturday 26 August 2017

Fragment caching in asp.net

Caching parts of webform is called as partial caching or fragment caching. In a web application development, there might be scenarios where most parts of the web page changes, but only a specific section of the page is static. Let's say that specific section also takes a long time to load. This is an ideal scenario, where fragment caching can be used. 

We will be using tblProducts table to understand fragment caching. Please use the script below to create and populate table tblProducts
Create Table tblProducts
(
Id int primary key,
Name nvarchar(50),
ProductDescription nvarchar(100)
)

Insert into tblProducts Values (1, 'Laptop''Dell Latitude Laptops')
Insert into tblProducts Values (2, 'iPhone''Apple iPhone 4S')
Insert into tblProducts Values (3, 'Desktop''Dell high performance desktops')
Insert into tblProducts Values (4, 'Server''HP Servers')

Script to create stored procedure that gets all the products. To introduce artificial query processing time, we are using "waitfor delay".
Create Procedure spGetProducts
as
Begin
Waitfor Delay '00:00:05'
Select from tblProducts
End

Steps to fragment cache a webform
1. Encapsulate that sepcific sections of the page that does not constantly change into a user control. 
2. Use the OutputCache directive on the user control to specify the cache settings.
3. Drag and drop the user control on the webform. 

Step 1: Encapsulate specific sections of the page that does not constantly change into a user control
Create an asp.net web application project. Add a user control to the project, with name "UCProductsControl.ascx". Copy and paste the following HTML in the ascx page of the user control.
<table style="border: 1px solid black">
    <tr>
        <td style="background-color: Gray; font-size:12pt">
            Products User Control
        </td>
    </tr>
    <tr>
        <td>
            <asp:GridView ID="GridView1" runat="server">
            </asp:GridView>
        </td>
    </tr>
    <tr>
        <td>
            <b>User Control Server Time:
                <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
            </b>
        </td>
    </tr>
    <tr>
        <td>
            <b>User Control Client Time:
                <script type="text/javascript">
                    document.write(Date());
                </script>
            </b>
        </td>
    </tr>
</table>

Copy and paste the following code in the code-behind file of the usercontrol
protected void Page_Load(object sender, EventArgs e)
{
    Label1.Text = DateTime.Now.ToString();
            
    string CS = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
    SqlConnection con = new SqlConnection(CS);
    SqlDataAdapter da = new SqlDataAdapter("spGetProducts", con);
    da.SelectCommand.CommandType = CommandType.StoredProcedure;
    DataSet DS = new DataSet();
    da.Fill(DS);

    GridView1.DataSource = DS;
    GridView1.DataBind();
}

Please make sure to include the following using declarations as well
using System.Data;
using System.Configuration;
using System.Data.SqlClient;

Step 2: Use the OutputCache directive on the user control to specify the cache settings
<%@ OutputCache Duration="60" VaryByParam="None" %>

Step 3: Drag and drop the user control on the webform
Copy and paste the following HTML on the webform.
<div style="font-family: Arial">
    <table style="border: 1px solid black">
        <tr>
            <td>
                Page content that changes
            </td>
        </tr>
        <tr>
            <td>
                <b>Page Server Time:
                    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
                </b>
            </td>
        </tr>
        <tr>
            <td>
                <b>Page Client Time:
                    <script type="text/javascript">
                        document.write(Date());
                    </script>
                </b>
            </td>
        </tr>
        <tr>
            <td>
                <br /><br />
                <uc1:UCProductsControl ID="UCProductsControl1" runat="server" />    
            </td>
        </tr>
    </table>
</div>

Copy and paste the following code in the code-behind file of the webform.
protected void Page_Load(object sender, EventArgs e)
{
    Label1.Text = DateTime.Now.ToString();
}

Notice that, when you run the web application, the user control is cached. The server time of the user control is not changed on refreshing the page but the other times on the user control and page changes. This proves that, the user control is cached, but not the rest of the webform. Fragment caching is that easy.

"Shared" attribute of the "OutputCache" directive: 
"Shared" attribute can be used with "OutputCache" directive, to cache a single response from a user control for use on multiple Web forms. By default, ASP.NET caches a separate response for each Web form that uses a cached user control. Let us understand this with an example.

Add another webform with name WebForm2.aspx to the asp.net web application. Copy and paste the relevant HTML and code from WebForm1.aspx onto WebForm2.aspx.

Run the application and navigate to WebForm1.aspx. It takes around 5 seconds to load. Now navigate to WebForm2.aspx, and notice that WebForm2.aspx also takes 5 minutes. Since by default, ASP.NET caches a separate response for each Web form that uses a cached user control, both WebForm1.aspx and WebForm2.aspx, are taking 5 seconds. 

Now, let's set the Shared="true" for "OutputCache" directive on "UCProductsControl" user control. This should cache a single response from the user control for use on WebForm1.aspx and WebForm2.aspx.
<%@ OutputCache Duration="60" VaryByParam="None" Shared="true" %>

Run the application and navigate to WebForm1.aspx. It takes around 5 seconds to load. Now navigate to WebForm2.aspx, and notice that WebForm2.aspx loads instantly. Also notice that, the server time of the user control is same on both the webforms. This proves that both WebForm1.aspx and WebForm2.aspx are using the single cached response of the user control. 

No comments:

Post a Comment