70-564 - Control Adapters

Filed under: , , , by:

When reviewing for the 70-564 exam  I did some practice with Control Adapters and more specifically ASP.NET Web Control Adapters and Page Adapters. It reminded me that not many .NET Web developers are aware of their existence, even though control adapters have been available since .NET 2.0. Of course it doesn't mean that every Web application must utilize a control adapter but in certain scenarios they might save a lot of time required to accomplish the same task without using control adapters. Simply, control adapters are controls that inherit from System.Web.UI.Adapters.ControlAdapter base class. Moreover, control adapters for ASP.NET Web Controls inherit from System.Web.UI.WebControls.Adapters.WebControlAdapter base class and ASP.NET page control adapters inherit from System.Web.UI.Adapters.PageAdapter base class. They are all abstract classes so to create a control adapter, one must inherit them. Control adapters adapt or modifies behavior at key points in the life cycle of the control for which a control adapter has been created. At each stage in the life cycle, where a call to a life cycle method is made, the ASP.NET page framework checks to see if there is an associated adapter for the control and calls on the adapter's associated method instead of the control's method. In many cases, the adapter method may simply defer back to the control's method. An exception to this behavior are adapters for state management in that the adaptive behavior is additive to the control's state. Control adapters are most commonly used to provide target-specific processing during a specific stage of the control life cycle or to customize target-specific rendering. WebControlAdapter class have additional several methods that are specific to rendering tags. PageAdapter class is the starting point for rendering a Web page adaptively. Additionally, the PageAdapter class defines properties and methods that enable adaptive rendering in the context of typical page-level tasks, such as caching or managing page-state persistence. So simply control adapters are a way of providing different renderings for controls without actually modifying the controls themselves. Because control adapters are designed to provide alternate renderings for different clients, you specify control adapter mappings in a .browser file, which is where associations between User Agent strings and browser capabilities are defined. Browser files can be added either in the local App_Browsers directory of an ASP.NET Web application or in the machine-wide %SYSTEM%\Microsoft.NET\Framework\v2.0.50727\Config\Browsers directory. Even though control adapters are associated with a specific browser type, they can be added to the Default.browser file and hence be applied to all clients. Below is an example of creating and using a page adapter, but the same rules apply for creating any control adapter.
ViewStatePageAdapter.cs

using System.Web.UI.Adapters;
using System.Web.UI;
public class ViewStatePageAdapter:PageAdapter 
{
public override PageStatePersister GetStatePersister()
{
return new SessionPageStatePersister(this.Page);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("Copyright 2009");
writer.RenderEndTag();
}
}
Default.browser
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.Page"
adapterType="ViewStatePageAdapter" />
</controlAdapters>
</browser>
</browsers>
Default.aspx.cs
public partial class _Default : System.Web.UI.Page 
{
protected override void OnPreRenderComplete(EventArgs e)
{
this.ClientScript.RegisterClientScriptBlock(
this.GetType(),
"DisplayViewState",
"<script>window.status=('ViewState: ' + document.forms[0]['__VIEWSTATE'].value.length + ' bytes');</script>");
}
}
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>View State Page Adapter Test</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" DataSourceID="AdvantureWorks" 
AllowPaging="True" AutoGenerateColumns="False" DataKeyNames="EmployeeID" 
PageSize="50" CellPadding="4" ForeColor="#333333" GridLines="None">
<RowStyle BackColor="#EFF3FB" />
<Columns>
<asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" 
InsertVisible="False" ReadOnly="True" SortExpression="EmployeeID" />
<asp:BoundField DataField="NationalIDNumber" HeaderText="NationalIDNumber" 
SortExpression="NationalIDNumber" />
<asp:BoundField DataField="ContactID" HeaderText="ContactID" 
SortExpression="ContactID" />
<asp:BoundField DataField="LoginID" HeaderText="LoginID" 
SortExpression="LoginID" />
<asp:BoundField DataField="ManagerID" HeaderText="ManagerID" 
SortExpression="ManagerID" />
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
<asp:BoundField DataField="BirthDate" HeaderText="BirthDate" 
SortExpression="BirthDate" />
<asp:BoundField DataField="MaritalStatus" HeaderText="MaritalStatus" 
SortExpression="MaritalStatus" />
<asp:BoundField DataField="Gender" HeaderText="Gender" 
SortExpression="Gender" />
<asp:BoundField DataField="HireDate" HeaderText="HireDate" 
SortExpression="HireDate" />
<asp:CheckBoxField DataField="SalariedFlag" HeaderText="SalariedFlag" 
SortExpression="SalariedFlag" />
<asp:BoundField DataField="VacationHours" HeaderText="VacationHours" 
SortExpression="VacationHours" />
<asp:BoundField DataField="SickLeaveHours" HeaderText="SickLeaveHours" 
SortExpression="SickLeaveHours" />
<asp:CheckBoxField DataField="CurrentFlag" HeaderText="CurrentFlag" 
SortExpression="CurrentFlag" />
<asp:BoundField DataField="rowguid" HeaderText="rowguid" 
SortExpression="rowguid" />
<asp:BoundField DataField="ModifiedDate" HeaderText="ModifiedDate" 
SortExpression="ModifiedDate" />
</Columns>
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<EditRowStyle BackColor="#2461BF" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
<asp:SqlDataSource ID="AdvantureWorks" runat="server" 
ConnectionString="<%$ ConnectionStrings:AdventureWorks %>" 
SelectCommand="SELECT HumanResources.Employee.* FROM HumanResources.Employee">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>
Here is the complete solution:


This sample Web Site uses a custom page adapter to store View State in a Web Server Session State. Also it adds to a page a div element with "Copyright 2009" text. A page adds in PreRenderComplete method a javascript that displays page ViewState size in client's browser status bar in order to see the difference of ViewState size with and without the ViewStatePageAdapter (to see the information on the view state size in IE7 and IE8 the following option must be enabled "Allow status bar updates via script").

The ViewStatePageAdapter has removed 25kB of View State infromation from a Web page, which means that 25kB less will be transfered to a client. Also the text we added to one control (PageAdapter) will be displayed in all pages. If a custom control or page adapter has been added go GAC and to machine-wide Default.browser file, it could affect all ASP.NET applications without really making any changes to those applications, so for example instead of displaying a regular page content it could display information about "Maintenance Break". The fact that control adapters can provide different rendering without actually modifying the controls themselves has been used to to create a suite of control adapters that change the rendering of several common ASP.NET controls to take better advantage of CSS (CSS-Friendly ASP.NET 2.0 Control Adapters). That made possible to have GridView control render using html div elements with css styles rather than html table. By looking at the huge power of control adapters, it is very obvious that any thriving ASP.NET developer should have a very good understanding of them and should not be afraid to use them only because there are other developers around that don't have any experience in using them, which is what I face from time to time and what I want to change through my posts.

0 comments: