By Omar Al Zabir
Book Price: $44.99 USD
£27.99 GBP
PDF Price: $35.99
Cover | Table of Contents | Colophon
UpdatePanel) for updating widgets without doing any postbacks, and it changes page layout by dragging and dropping widgets on the page. It also offers a rich collection of Control Extenders that add cool effects like fade in/fade out, smooth transitions, and client-side animations. You can add to the rich client-side experience by providing autocompletion behavior on text boxes, asynchronous data loading via web service calls, client-side paging, sorting, and much more.Entity classes out of database rows and vice versa.
IWidget—a custom interface—to integrate with the widget framework and use the services provided by the core framework we use for the application. A custom-built Ajax control extender provides the drag-and-drop feature for the widgets. The widget frame-work and its core are explained later in this chapter (see the "Using a Widget Framework" section).
DashboardFacade (see ).
DashboardFacade to perform operations such as adding a new tab or widget, or storing a widget state. DashboardFacade invokes different workflows for different operations. The workflows do the real work and are developed using Windows Workflow Foundation (WF), as explained in . Each workflow consists of one or more activities. Each activity is like a class that performs some unit task. Activities use the DatabaseHelper and DashboardDataContext classes to work with the database. DatabaseHelper is a class used for performing common database operations. DashboardDataContext is generated by LINQ to SQL and maps entities to database tables.
Panel that contains all the elements for the customization area. By default, the Panel is invisible, but the widget makes it visible when it is notified that a user has clicked the "edit" link.IWidget interface, which defines how the widget container communicates with the widget (see ).
public interface IWidget
{
void Init(IWidgetHost host);
void ShowSettings();
void HideSettings();
void Minimized();
void Maximized();
void Closed();
}
IWidget interface defines a way to inform the widget when to initialize the widget area and restore its state. When a user clicks the "edit" link, ShowSettings informs the widget to show the settings area. When a user clicks the maximize or minimize links (the plus or minus icons), Maximized and Minimized functions are called. The same happens when a user closes the widget—Closed is called and the widget cleanups any information stored in database. These are all post-event callback methods—actions the user has already performed and the widget reacts to.IWidget—a simple interface implementation.IWidgetHost via the IWidget.Init method. This interface exposes methods to communicate with the container as well as the services provided by the container. IWidgetHost
for( int i = 0; i < 100000; i ++ )
{
WebClient client = new WebClient();
client.DownloadString("http://www.dropthings.com/default.aspx");
}
ActionValidator class maintains a count of specific actions such as first visit, revisit, asynchronous postbacks, adding a new widget, adding a new page, etc. It checks whether the count for a specific IP exceeds the threshold value or not. The following code shows the enumeration that contains the type of actions to check for and their threshold value for a specific duration, which is 10 minutes:
public static class ActionValidator
{
private const int DURATION = 10; // 10 min period
public enum ActionTypeEnum
{
FirstVisit = 100, // The most expensive one, choose the value wisely
ReVisit = 1000, // Welcome to revisit as many times as the user likes
Postback = 5000, // Not much of a problem
AddNewWidget = 100,
AddNewPage = 100,
}
IsValid does the check. It returns true if the request limit is not passed and false if the request needs to be denied. Once you return false, you can call IWidget and IWidgetHost interfaces. Then you will put it all together and build a Flickr photo widget and a RSS widget. Finally, you will use ASP.NET 2.0 Membership and Profile providers to implement authentication, authorization, and profiles.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_
Default" Theme="Default" EnableSessionState="False" %>
<%@ OutputCache Location="None" NoStore="true" %>
<%@ Register Src="Header.ascx" TagName="Header" TagPrefix="uc1" %>
<%@ Register Src="Footer.ascx" TagName="Footer" TagPrefix="uc2" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
TagPrefix="ajaxToolkit" %>
<%@ Register Assembly="CustomDragDrop" Namespace="CustomDragDrop" TagPrefix="cdd" %>
<%@ Register Src="WidgetContainer.ascx" TagName="WidgetContainer" TagPrefix="widget" %>
<!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 id="Head1" runat="server">
<title>Ajax Web Portal</title>
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_
Default" Theme="Default" EnableSessionState="False" %>
<%@ OutputCache Location="None" NoStore="true" %>
<%@ Register Src="Header.ascx" TagName="Header" TagPrefix="uc1" %>
<%@ Register Src="Footer.ascx" TagName="Footer" TagPrefix="uc2" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
TagPrefix="ajaxToolkit" %>
<%@ Register Assembly="CustomDragDrop" Namespace="CustomDragDrop" TagPrefix="cdd" %>
<%@ Register Src="WidgetContainer.ascx" TagName="WidgetContainer" TagPrefix="widget" %>
<!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 id="Head1" runat="server">
<title>Ajax Web Portal</title>
WidgetContainer control, which is the web control for the widget container.CustomDragDrop assembly, which contains the CustomDragDropExtender and the CustomFloatingBehavior.DragPanel extender that could be used to provide drag-and-drop support to panels. It also has a ReorderList control, which could reorder the items into a single list. Widgets are basically panels that flow vertically in each column. So, it could be possible to create a reorder list in each column and use the DragPanel to drag the widgets. But ReorderList couldn't be used because:UpdatePanel per column.ReorderList can't create another drag handle.DragPanel extender. The default implementation of drag and drop in the Ajax Control Toolkit doesn't work for these reasons:WidgetContainer dynamically creates a widget inside its body area. The container consists only of header and body areas. The rest is provided by the actual widget loaded dynamically inside the container's body area. The settings area that you see when you click"edit" on the header also comes from the actual widget. WidgetContainer informs the widget only when to show it. The "Building Widgets" section later in this chapter shows how the widget handles this notification. WidgetContainer acts as a bridge between widgets and the core. The core communicates to the widgets via the container, and the widgets use the core's features via the container.WidgetContainer's header contains the title text, the expand and collapse button, the "edit" link, and the close button within an UpdatePanel, as shown in .
<asp:Panel ID="Widget" CssClass="widget" runat="server">
<asp:Panel id="WidgetHeader" CssClass="widget_header" runat="server">
<asp:UpdatePanel ID="WidgetHeaderUpdatePanel" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
...
...
...
</ContentTemplate>
</asp:UpdatePanel>
</asp:Panel>
UpdatePanel controls.UpdateProgress extender attached to the header UpdatePanel, which shows a "Working…" indicator when the header is going through asynchronous postback. This happens when a user clicks on the title to change it or clicks some button on the header area.<asp:UpdateProgress ID="UpdateProgress2" runat="server" DisplayAfter="10" AssociatedUpdatePanelID="WidgetHeaderUpdatePanel" > <ProgressTemplate> <center>Working...</center> </ProgressTemplate> </asp:UpdateProgress>
WidgetContainer, let's lookat how you build the widgets it hosts. First, we'll create a simple widget to display Flickr photos, followed by another widget to display RSS and Atom feeds.
<?xml version="1.0" encoding="utf-8" ?> <rsp stat="ok"> <photos page="1" pages="10" perpage="100" total="1000"> <photo id="431247461" owner="25524911@N00" secret="cb9370fd16" server="162" farm="1" title="P1020899" ispublic="1" isfriend="0" isfamily="0" /> <photo id="431247462" owner="46871506@N00" secret="036edda0e9" server="188" farm="1" title="black" ispublic="1" isfriend="0" isfamily="0" /> <photo id="431247458" owner="91583992@N00" secret="6cd9a27d6d" server="153" farm="1" title="DSC00647" ispublic="1" isfriend="0" isfamily="0" />
XElement from an URL:var xroot = XElement.Load(url);
PhotoInfo class for convenient processing:
var photos = (from photo in xroot.Element("photos").Elements("photo")
select new PhotoInfo
{
Id = (string)photo.Attribute("id"),
Owner = (string)photo.Attribute("owner"),
Title = (string)photo.Attribute("title"),
Secret = (string)photo.Attribute("secret"),
Server = (string)photo.Attribute("server"),
Farm = (string)photo.Attribute("Farm")
})