Showing posts with label WEB. Show all posts
Showing posts with label WEB. Show all posts

Thursday, June 6, 2013

SignalR – Real-time application development

Introduction

Real-time applications for the web are none other than usual client-server applications with one distinct feature, that being they accomplish functionality with very little (near real-time) or zero latency (real-time). There have been a number of traditional approaches in the past that were employed in order to achieve such functionality suing a variety of methodologies. One such mechanism is Comet, which is an umbrella term that provides a variety of models/solutions in order to achieve real-time application development over HTTP (Hyper Text Transfer Protocol) (e.g. Streaming, Hidden iframe, Ajax with long polling, etc.).
 
There are a number of third-party frameworks available today, until recent Microsoft had no streamlined mechanism that enabled a straightforward approach in the implementation of real-time applications. Although frameworks such as WCF (Windows Communication Foundation) did support a similar functionality using a couple of bindings, wsDualHttpBinding for web services and httpPollingDuplex Silverlight based applications, they had limited features in terms of scale and functionality. Apart from that, you were pretty much on your own if you needed to develop an application that required real-time functionally using ASP.NET.
 

Limitations of a typical Request-Response oriented Application

HTTP functions on the request-response principle, where the client makes a request and the server responds. This is the case with any application web application that runs on HTTP. This is illustrated below,
 
 Request response
 
This mechanism does not provide us the means to achieve real-time data transfer, mainly due to the reason that the server is not able to provide any updated unless the client specifically requests for it. One typical way that developers utilized to overcome this limitation is by performing periodic polling, where the client keeps on requesting until the server has an update to provide the client with as illustrated below,
 
 
Although the above mechanism tries to eliminate the afore mentioned drawback of implementing real-time web application using HTTP, it still could not be considered as an appropriate solution.
 

ASP.NET SignalR

ASP.NET SignalR is a framework maintained and developed by Microsoft that provides just the right functionality that helps you achieve seamless development of real-time applications using ASP.NET. SignalR incorporates a variety of mechanisms/modes that help handle failover during failure to negotiate on a specific transport mechanism to perform real-time message exchange. The framework also supports a straight forward development approach by exposing an API over the core functionality enabling you to develop applications in a breeze. SignalR is written so that it is scalable as you application grows and perform well even when the application requires handling many concurrent users at a given time.
 
SignalR provided four mechanisms in order to overcome the limitations associated with the traditional HTTP request-response principal during development of real-time web applications. Two of these mechanisms use new features introduced with HTML5 version, which are WS (Web-Sockets) and SSE (Server-Sent-Events). As of writing these two features are currently as draft within the HTML5 specification, although most modern browsers do support these features and will continue to evolve in future. The other two mechanisms SignalR supports are Forever Frame and Long Polling.
 
Upon SignalR framework being integrated to an application the framework will choose one of the best mechanisms based on the browser/server capabilities and agree on the transport negotiate accordingly. From a developer standpoint all that you will do is code against the high-level API that will encapsulate the negotiation of which mechanism to use. The key point to understand is that the code you write using framework is the “SAME” regardless of which transport mode you use. Listed below is more information on each of the transport modes supported by SignalR.
 

WS (Web-Sockets)

WS is a new protocol (i.e. ws:// or wss://) introduced with HTML5 and is the most appropriate technology for building real-time applications. That is due to the fact that WS enables creation of a Full-Duplex Bidirectional channel over HTTP enabling the client or the server to send messages independently.
 
 
As illustrated above upon the client creating a WS connection between the servers both server and client will utilize a full-duplex channel over HTTP enabling the server to send event data and the client to send data via the same connection. WS is the preferred over the other options below, due to the fact that it is very preformant and less resource intensive in its essence.
 
This feature is a new addition to HTML and hence requires alterations on an architectural level. Hence it requires that WS be supported in the web server, client browser and all intermediate associates (e.g. proxies, firewalls and server, client, public network infrastructures).In order to enable WS with ASP.NET the prerequisites are that the application must be running on ASP.NET 4.5 or MVC 4, IIS8 (or IIS8 express within Windows Server 2012) with a WS compatible browser.
 

SSE (Server-Sent-Events)

SSE is again an HTML5 feature which enables event based streaming over HTTP. On the contrary to WS, SSE is a mere addition to the JS API (i.e. EventSource object), hence requiring no major change architecturally. This feature is supported by most browsers available today.
 
 
SSE is not a duplex connection like WS. As illustrated above it is a one way connection so that the server can send updates to the client. SSE is achieved by the client creating an EventSource object via JS and the server flushing event data as and when there is an update triggered without terminating the stream. Should there be any client update to be sent, this will be sent via a separate request to the server and not using the event source created between the server and the client which can be considered somewhat of a limitation.
 

Forever Frame

This mechanism is a way of using existing HTML functionality to utilize real-time functionality. It is achieved by creating a hidden iframe within the client to connect to the server and use scriptlets sent by the server to trigger update within the client page. The functionality is similar to using SSE, although in this case this technique uses available HTML iframe element in order to achieve the similar functionality.
 
 
As illustrated the scirptlets sent by the server are appended to the iframe body and a mechanism of reading the script and executing it will be handled by the client accordingly.
 

Long Polling

This is technique that works across all browsers. Long polling is a last resort used by SignalR when determining a transport mechanism to use. Long polling functions in a manner that it sends Ajax based requests to the server where the server holds on to the request for a definite period of time and terminates the request with an empty response. However in cases where there is an server event that needs to be sent across to the client the server immediately sends the response for the client to use, and the client initiates another request to server that will again listen to any server update available.
 
 
Long Polling is considered more resource intensive compared to the other methods supported by SignalR. This is mainly due to the continuous connection initiated and terminated between he server and the client.
 

SignalR transport precedence

The above four mechanisms are supported by the SignalR framework and it will utilize the most effective based on the capabilities of the client/server and fallback to another mechanism if failed. The order of fallback within the framework is as follows,
1. Web-Sockets: SignalR will try to determine if the server/client or intermediate channels support Web-Sockets and use it.
2. Server-Sent-Events: Falls back from Web-Sockets if the browser supports Server-Sent-Events.
3. Forever Frame: Falls back from Server-Sent-Events if the browser supports this mechanism.
4. Long-Polling: Is the fail safe mechanism utilized by SignalR in cases where none of the above technologies are supported.
 

Summary

SignalR is a framework maintained by Microsoft and provides features and means of how real-time messaging can be achieve between the client and the server over HTTP. SignalR supports four main mechanisms of transport (i.e. Web-Sockets, Server-Sent-Events, Forever Frame and Long Polling). SignalR also provides and intuitive API and exposes multiple programing models that aids ease of development which will be looked at in a future post and demos.

Sunday, July 15, 2012

Tree View Checkbox JQuery Selection

Adding JQuery Hierachical Selection

Asp.Net TreeView control is a useful control when hierarchical data representation is required in an .aspx page. The Treeview control inherently supports enabling of checkboxes for node level selection. I came a across a problem where I needed a solution for the following, 1. Checking a node should cause all its child nodes to be selected. 2. Checking a node should cause all its parent nodes to be selected. In order to this it was just a matter of adding a few lines of JQuery to the aspx page. Thanks to JQuery’s wealth of convenient methods it resulted in a few lines. Listed below is the javascript code for your reference.

You can download the DEMO solution from here.

Monday, July 2, 2012

Asp.Net Multiple Row Edit GridView Control

Multiple Row Edit GridView Control

About the ASP.NET Gridview

The Asp.Net GridView control is a versatile control when a web based application requires tabular data that can be manipulated with. It enables not just presentation of data but also extended functionality to perform selecting, editing, deleting and paging to name a few.

ASP.NET Gridview Limitaions

I recently came across a requirement which required providing functionality to edit multiple rows in the GridView. The GridView by default provides the ability to edit a single row at a given instance which was not sufficient. Upon my research I came across few examples on the web that suggested the use of a page wide variable which could be combined with the Visible property of controls added within the ItemTemplate of the GridView control similar to the following,
<ItemTemplate>
    <asp:Label ID="lblProductName" Visible='<%# !(bool) IsEditMode %>' runat="server" Text='<%# Eval("ProductName") %>' />
    <asp:TextBox ID="txtProductName" Visible='<%# IsEditMode %>' runat="server" Text='<%# Eval("ProductName") %>' />
</ItemTemplate>
The IsEditMode property in the above code segment is a page wide variable which will be set to true upon the user requesting to edit rows. This method has several drawbacks as follows,
  1. Changes all rows to edit mode. Cannot selectively specify which rows to edit. 
  2. All controls are placed within the ItemTemplate tag of the GridView thus making it difficult to clearly differentiate between item and edit controls. 
  3. If many GridViews are available the developer is required to take responsibility of managing global properties that enable the edit mode of each grid.

Enabling ASP.NET Gridview Mulitiple Row Edit

In order to rectify this I spent some time trying to extend the GridView control which mitigates the above mentioned drawbacks and enable multiple edit. I will go thru the most important code with you that enable these features in order to help you understand. You can download the code from here.

Step 1: Adding the check box column for row selection

In order to provide the user with the ability to select the rows to be edited it was evident that a checkbox column was required. This is achieved by adding a TemplateField to the GridView control where the TemplateField instances ItemTemplate and HeaderTemplate properties to an implementation that contains a CheckBox control for header and row selection, thereby adding the constructed TemplateFiled to the GridViews column collection. In essence what we are required to do is create a class that implements the ITemplate interface in the System.Web.UI namespace which will provide the method stubs for our custom implementation of the TemplateField instances ItemTemplate and HeaderTemplate. Listed in the below code block is the implementation of the custom CheckBoxTemplate,
///<summary> 
/// The selector check box template colum class.
/// </summary>
public class CheckBoxTemplate : ITemplate
{
    private ListItemType Type { get; set; }

    ///<summary> 
    /// Initializes a new instance of the class.
    /// </summary>
    ///The item type.
    public CheckBoxTemplate(ListItemType type)
    {
        this.Type = type;
    }

    public void InstantiateIn(Control container)
    {
        switch (Type)
        {
            case ListItemType.Header: goto default;
            case ListItemType.Item: goto default;
            default:
                    CheckBox chkSelector = new CheckBox();
                    chkSelector.Checked = false;
                    // The selector attribute is used by the JS code in MultiEditGridView.js file.
                    chkSelector.InputAttributes.Add("selector", Type == ListItemType.Header ? "headerCheckBox" : "rowCheckBox");
                    // Call the appropriate function in the MultiEditGridView.js file based on the checkbox style.
                    chkSelector.InputAttributes.Add("onClick", Type == ListItemType.Header ? "MultiEditHeaderCheckBoxSelect(this)" : "MultiEditRowCheckBoxSelect(this)");
                    container.Controls.Add(chkSelector);
                    break;
        }

    }
}
Note the constructor of the class that requests a ListItemType type in System.Web.UI.WebControls namespace to differentiate between the types of templates being created. The reason for this is because I required different client side behavior via JavaScript for the header checkbox and row level checkboxes such that when the header checkbox is checked all corresponding row level check boxes are checked and when all row level checkboxes are selected the header checkbox is checked. This implementation is performed in the InstatiateIn method at line 17. Last but not least to add the checkbox column to the grid we are required to create a TemplateField instance that has its ItemTemplate and HeaderTemplate set to an implementation of the custom CheckBoxTemplate class. This is performed in the overridden CreateColumns(…., ….) method of the MultiEditGridView class. When adding the customized TemplateField we need to verify that the check box column is always the first column in the grid. The following code block lists the code in achieving this aspect,
 
Note the highlighted rows in the code block above. Since we need to make sure the customized checkbox TemplateField is added as the first column we first request the base.GridView base.CreateColumns(…., ….) in creating the default columns fields (line 3) and finally insert the customized TemplateField at the first position (line 11).

Step 2: Switching the selected rows to edit mode

Upon the user selecting several/all checkboxes we need to toggle the stated of each row likewise. This is accoumplished in the overridden CreateRow(…., …., …., ….) method. The following code block details this,
protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource)
{
    ArrayList columnCollection = (ArrayList)base.CreateColumns(dataSource, useDataSource);

    // Appends an additional column to the beginining of the grid if multi edit is enabled.
    if (EnableMultiEdit)
    {
        SelectorTemplateFiled.HeaderTemplate = new CheckBoxTemplate(ListItemType.Header);
        SelectorTemplateFiled.ItemTemplate = new CheckBoxTemplate(ListItemType.Item);

        columnCollection.Insert(0, SelectorTemplateFiled);
    }

    return columnCollection;
}
Note the if condition (Line 4). It verifies if the grid is currently in edit mode and if the current row index is contained in the EditIndexes collection, effectively toggling the ItemTemplate or EditTemplate of the grid row (line 6 and line 9).

Step 3: Providing an overloaded DataBind() method

The GridView controls DataBind() method will not provide an indication if the grid is required to toggle edit mode on/off. Hence we need to overload the DataBind() by providing a DataBind(….) method to provide support for the developer to if required toggle the edit mode on/off. Listed below is the code block that achieves this,
protected override GridViewRow CreateRow(int rowIndex, int dataSourceIndex, DataControlRowType rowType, DataControlRowState rowState)
{
    // Enbles the edit template if any of the checkbox indexes are selected.
    if (EditFlag && EditIndexes.Contains(rowIndex))
    {
        return base.CreateRow(rowIndex, dataSourceIndex, rowType, DataControlRowState.Edit);
    }
    else
        return base.CreateRow(rowIndex, dataSourceIndex, rowType, rowState);
}
Based on the isEtidEnabled parameter of the DataBind(….) method the MultiEditGridView will toggle edit mode as specified in the earlier section. This method initializes the properties that will be used on by the overridden CreateRow(…., …., …., ….) method. Note the foreach loop where the EditIndexes are populated based on the selection of the custom checkbox TemplateField. Finally we call the GridView controls DataBind() method to perform the usual binding which will call the overridden methods in sequence.

Step 4: Additional Information

The custom checkbox TemplateField column related JavaScript is located in the MultiEditGridView.js file and in order to render the script when the control it is require that we register the script on the page. Listed below is code block that achieves this.
protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);

    // Register the JS on page.
    Page.ClientScript.RegisterClientScriptResource(typeof(CustomControls.MultiEditGridView), "CustomControls.MultiEditGridView.js");
}
Note the RegisterClientScriptResouce(…., ….) method which specifies which type of control will register the script (MultiEditGridView in this case) and the name of the resource to be registered. When using this method it is important that the MultiEditGridView.js is set to be an Embedded Resource under the properties window. Additionally it is also important that the following code is added in the AssemblyInfo.cs file for the required functionality,
// Add the MultiEditGridView.js as a web resource.
[assembly: WebResource("CustomControls.MultiEditGridView.js", "text/javascript")]

Step 5: Using the MultiEditGridView control

In order to use the MultiEditGridView control add the CustomControls project to the web solution you are working on and add a reference to the CustomControls project. Rebuild the whole solution. Go ahead and drag the MultiEditGridView to your page. Create the required template fields based on datasource.
 
NOTE: The embeded JavaScript of the MultiEditGridView is based on JQuery. Hence you will need to have a refference to the JQuery API from your web application.

Summary

Listed below is an example of a sample implementation (Click to expand the code section), Products.aspx page
 
Products.aspx page
<script type="text/javascript" src="Scripts/jquery-1.4.4.min.js"></script></pre>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Products.aspx.cs" Inherits="MultiEditGridViewDemo.Products" %>
<%@ Register Assembly="CustomControls" Namespace="CustomControls" TagPrefix="cc" %>
<!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>Multi Edit Grid View Demo</title>
    <script src="Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
</head>
<body>
    <form id="form1" runat="server">
    <cc:MultiEditGridView ID="MultiEditGridView1" runat="server" AutoGenerateColumns="False">
        <Columns>
            <asp:TemplateField HeaderText="Product Name">
                <ItemTemplate>
                    <asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>'></asp:Label>
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:TextBox ID="txtName" runat="server" Text='<%# Eval("Name") %>'></asp:TextBox>
                </EditItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Product Category">
                <ItemTemplate>
                    <asp:Label ID="lblCategory" runat="server" Text='<%# Eval("Category") %>'></asp:Label>
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:TextBox ID="txtCategory" runat="server" Text='<%# Eval("Category") %>'></asp:TextBox>
                </EditItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Product Description">
                <ItemTemplate>
                    <asp:Label ID="lblDescription" runat="server" Text='<%# Eval("Description") %>'></asp:Label>
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:TextBox ID="txtDescription" runat="server" Text='<%# Eval("Name") %>'></asp:TextBox>
                </EditItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Is Available">
                <ItemTemplate>
                    <asp:CheckBox ID="chkIsAvailable" runat="server" Checked='<%# Eval("IsAvailable") %>' Enabled="false">
                    </asp:CheckBox>
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:CheckBox ID="chkIsAvailable" runat="server" Checked='<%# Eval("IsAvailable") %>'>
                    </asp:CheckBox>
                </EditItemTemplate>
            </asp:TemplateField>
        </Columns>
    </cc:MultiEditGridView>
    <br />
    <asp:Button ID="btnEdit" runat="server" OnClick="btnEdit_Click" Text="Edit" />
    <asp:Button ID="btnUpdate" runat="server" OnClick="btnUpdate_Click" Text="Update" />
    </form>
</body>
</html>
Products.aspx.cs page
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MultiEditGridViewDemo
{
    public partial class Products : System.Web.UI.Page
    {
        public bool IsEdit { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                BindGridData(false);
            }
        }

        private void BindGridData(bool isEnableEdit)
        {
            List productList = new List {
                    new Product{ ID=1, Name="Product 1", Category="Category 1", Description="Product 1 - Category 1", IsAvailable=false },
                    new Product{ ID=1, Name="Product 2", Category="Category 4", Description="Product 2 - Category 4", IsAvailable=true },
                    new Product{ ID=1, Name="Product 3", Category="Category 3", Description="Product 3 - Category 3", IsAvailable=true },
                    new Product{ ID=1, Name="Product 4", Category="Category 1", Description="Product 4 - Category 1", IsAvailable=false },
                    new Product{ ID=1, Name="Product 5", Category="Category 5", Description="Product 5 - Category 5", IsAvailable=true },
                    new Product{ ID=1, Name="Product 6", Category="Category 6", Description="Product 6 - Category 6", IsAvailable=true },
                    new Product{ ID=1, Name="Product 7", Category="Category 2", Description="Product 7 - Category 2", IsAvailable=false },
                    new Product{ ID=1, Name="Product 8", Category="Category 5", Description="Product 8 - Category 5", IsAvailable=true },
                    new Product{ ID=1, Name="Product 9", Category="Category 3", Description="Product 9 - Category 3", IsAvailable=true },
                    new Product{ ID=1, Name="Product 10", Category="Category 3", Description="Product 10 - Category 3" , IsAvailable=false }
                };

            MultiEditGridView1.DataSource = productList;
            MultiEditGridView1.DataBind(isEnableEdit);
        }

        protected void btnEdit_Click(object sender, EventArgs e)
        {
            BindGridData(true);
        }

        protected void btnUpdate_Click(object sender, EventArgs e)
        {
            BindGridData(false);
        }
    }

    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public string Description { get; set; }
        public bool IsAvailable { get; set; }
    }
}
 
I encourage you to download the attached solution which consists of the extended GridView control MultiEditGridView and a sample web application demonstrating its features, thereby providing me your feedback on further improvements I could incorporate.

About Me

I am a software developer with over 7+ years of experience, particularly interested in distributed enterprise application development where my focus is on development with the usage of .Net, Java and any other technology that fascinate me.