Showing posts with label JQuery. Show all posts
Showing posts with label JQuery. Show all posts

Monday, September 27, 2010

How to show the selected image file without saving file in the disk before upload


Demo:
 
I was thinking a way to show images before actually uploading them to server. I would say to preview images using javascript. Obviously asp.net file input control does not like post-backs when it has a selected file. This idea is to preview the selected image by saving the file as byte[] array in the session and assigning the file to a src (ImageUrl) of a image element(asp.net Image) in a subsequent request. I have used jQuery to simplify the battle with asp.net rendered domain model. First hurdle, simple jQuery ajax didnt posted my selected image file. So I needed to find a way to post my selected file, then found a nice little plugin so called jQuery AjaxForm. This plugin nicely did the trick. I manage to change the form action for a bit and post the form to GenericHanlder. As soon I found the posted file, I get the converted file in to a System.Drawing.Image and saved it in the session. Finally carefully reverted the asp.net from action to it's original value.
HttpPostedFile file = context.Request.Files[0];
image = Bitmap.FromStream(file.InputStream);
context.Session["image"] = image;
If we request GenericHanlder again, it can retreive the image from session and serve as an image. So what I did was in the success event of jQuery AjaxForm post, assign the GenericHandler.ashx to src of the preview image. As a result, there will be a second subsequent request just after the first form post to the Generic Hander. Now I distinguish the two requests and for the second request I serve the image from the session after converting image object in to a byte[] array using a momery stream.
MemoryStream stream = new MemoryStream();
image.Save(stream, format);
context.Response.BinaryWrite(stream.ToArray());
Download jQuery Ajax Form
Download jQuery
Memeory Consumption with heavy load:
Saving the image in the session is only between two consecutive requests. First request creates the image and save it in the session. Then the second request consumes the image, remove the image from session and dispose it. So memory use of the server is instantaneous. Producer consumer fashion.

Markup:
<%@ Page Language="C#" %>
<html>
<head id="Head2" runat="server">
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery-form.js" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        function ShowFile() {
            var formId = '<%= this.Form.ClientID %>';
            var imageId = '<%=this.imageView.ClientID %>';
            var fileUploadId = '<%=fuFileUpload.UniqueID %>';
            var r = Math.floor(Math.random() * 999999);
            var action = $('#' + formId).attr('action');
            $('#' + formId).attr('action''GenericHandler.ashx?f=' + fileUploadId);
            $('#' + formId).ajaxForm(function () {
                $('#' + imageId).attr('src''GenericHandler.ashx?s=' + fileUploadId + '&r=' + r);
                $('#' + imageId).show();
                $('#' + formId).attr('action', action);
            });
            $('#' + formId).submit();
        }
    </script>
</head>
<body>
    <form id="form2" runat="server">
    <asp:FileUpload runat="server" ID="fuFileUpload" onchange="javascript:ShowFile();" />
    <asp:Button ID="Button1" runat="server" Text="Save" />
    <hr />
    <asp:Image ID="imageView" runat="server" alt="Thumbnail" Style="displaynone" />
    </form>
</body>
</html>

Generic Handler:
public class GenericHandler : IHttpHandlerIRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        string f = context.Request.QueryString.Get("f");
        string s = context.Request.QueryString.Get("s");
        if (!string.IsNullOrEmpty(f))
        {
            HttpPostedFile file = context.Request.Files[f];
            if (file == null)
                HttpContext.Current.ApplicationInstance.CompleteRequest();
            else
            {
                List<string> keys = new List<string>();
                foreach (string key in context.Session.Keys) if (key.StartsWith(f)) keys.Add(key);
                foreach (string key in keys) context.Session.Remove(key);
                System.Drawing.Image image = Bitmap.FromStream(file.InputStream);
                context.Session[f + "image"] = image;
                context.Session[f + "contextType"] = context.Request.Files[0].ContentType;
                context.Response.Flush();
                HttpContext.Current.ApplicationInstance.CompleteRequest();
            }
        }
        else if (!string.IsNullOrEmpty(s))
        {
            string ck = s + "contextType";
            string ik = s + "image";
            if (context.Session[ck] == null || context.Session[ik] == null)
            {
                HttpContext.Current.ApplicationInstance.CompleteRequest();
                if (context.Session[ck] != null) context.Session.Remove(ck);
                if (context.Session[ik] != null) context.Session.Remove(ik);
            }
            else
            {
                using (System.Drawing.Image image = (System.Drawing.Image)context.Session[ik])
                {
                    context.Response.Clear();
                    context.Response.ClearHeaders();
                    string type = context.Session[ck].ToString().ToLower();
                    System.Drawing.Imaging.ImageFormat format = 
                                                            System.Drawing.Imaging.ImageFormat.Gif;
                    bool isValid = true;
                    if (type.Contains("bmp")) format = System.Drawing.Imaging.ImageFormat.Bmp;
                    else if (type.Contains("jpg") || type.Contains("jpeg")) format = 
                                                            System.Drawing.Imaging.ImageFormat.Jpeg;
                    else if (type.Contains("png")) format = System.Drawing.Imaging.ImageFormat.Png;
                    else if (type.Contains("gif")) format = System.Drawing.Imaging.ImageFormat.Gif;
                    else if (type.Contains("wmf")) format = System.Drawing.Imaging.ImageFormat.Wmf;
                    else if (type.Contains("tiff") || type.Contains("tif")) format = 
                                                            System.Drawing.Imaging.ImageFormat.Tiff;
                    else if (type.Contains("exif")) format = System.Drawing.Imaging.ImageFormat.Exif;
                    else isValid = false;
                    if (isValid)
                    {
                        using (MemoryStream stream = new MemoryStream())
                        {
                            image.Save(stream, format);
                            context.Response.BinaryWrite(stream.ToArray());
                            context.Response.ContentType = type;
                        }
                    }
                    context.Session.Remove(ck);
                    context.Session.Remove(ik);
                    HttpContext.Current.ApplicationInstance.CompleteRequest();
                }
            }
        }
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

References:
Many thanks to following people for their work, without them I would not have achive this.
  1. jQuery Form:
  2. Converting image to a byte stream:
  3. Generating random number usign java script:

Sunday, September 26, 2010

How to save only changes (stop posting back if there are no any changes)

Demo:
For this we can utlize a nice little jQuery plugin called DirtyForm
Download dirty form:
Download jQuery:
Example:
<%@ Page Language="C#"  %>
<html>
<head id="Head1" runat="server">
 <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
 <script src="Scripts/jquery-dirtyform.js" type="text/javascript"></script>
 <script language="javascript" type="text/javascript">
     var isDirty = false;
     $(document).ready(function () {
         $('#<%= this.Form.ClientID %>')
     .dirty_form()
     .dirty(function (event, data) {
         isDirty = true;
     });
     });
     function Save() {
         if (!isDirty) {
             alert("You didn't change anything");
             return false;
         }
         return true;
     }
 </script>
 <script runat="server">
  protected void Save(object sender, EventArgs e)
  {
       this.lblUpdateTime.Text = string.Format("Last Updated On: {0}", DateTime.Now.ToString("hh:mm:ss"));
  }
 </script>
</head>
  <body>    
    <form id="form1" runat="server">
        <asp:TextBox runat="server" ID="txtName"></asp:TextBox><br />
        <asp:TextBox runat="server" ID="txtAddress"></asp:TextBox><br />
        <asp:TextBox runat="server" ID="txtPostcode"></asp:TextBox><br />
        <asp:TextBox runat="server" ID="txtEmail"></asp:TextBox><br />
        <asp:Button 
            runat="server" 
            ID="btnSave" 
            OnClick="Save" 
            OnClientClick="return Save();" 
            Text="Save" /><br />
        <asp:Label runat="server" ID="lblUpdateTime" />        
     </form>
   </body>
</html>

Saturday, September 18, 2010

How to dynamically load a DropDownList using jQuery and JSON


Demo:

If you want to load dropdownlist on the spot, you can use onmouseover and onfocus events to respond both mouse and keyboard. I would use jQuery + JSON to load dropdownlists dynamically which will be the ideal case. I have used GenericHander.ashx to servie all the dropdownlist data.

But the problem is when you add/change dropdown list items in the client side using JavaScripts, in the very next postback, it fails the EventValidation I am not going to discuss about this issue here. But I have a seperate article with detailed information how to overcome this issue. So I have used used AddableDropDownList for this example.

Other key point is, you have to remember load items to the list only the first page load inside the JavaScript. Because once you added items to the list they will get listed in AddableDropDownList.Items collection and they will be in ViewState for subsequent postbacks. So no need to load on each postback.

Markup - Test Page
<%@ Register Assembly="ActiveTest" Namespace="ActiveTest" TagPrefix="asp" %>
<%@ Page Language="C#" %>
<html>
<head runat="server">
    <style type="text/css">
        .countries { width:150px; }
    </style>        
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        var countriesLoaded = false;
        function load(key) {
            if ('<%=this.IsPostBack %>' != 'True') {
                if (key == 'countries' && countriesLoaded) return;
                var target = $("." + key);
                target.attr("disabled""disabled");
                $.getJSON('GenericHandler.ashx?q=' + key, function (data) {
                    for (i = 0; i < data.length; i++)
                        AddListItem(data[i].value, data[i].text, '<%=AddableDropDownList1.ClientID %>');
                    countriesLoaded = true;
                    target.removeAttr("disabled");
                });
            }
        }
    </script>
    <script runat="server">
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (this.IsPostBack)
                this.lblLstPostBackTime.Text = 
                    string.Format("Last posted pack at: {0}"DateTime.Now.ToString("hh:mm:ss"));
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:AddableDropDownList
            ID="AddableDropDownList1" 
            runat="server" 
            CssClass="countries" 
            onmouseover="javascript:load('countries')" 
            onfocus="javascript:load('countries')">
            <asp:ListItem>Please Select</asp:ListItem>
        </asp:AddableDropDownList>
        <hr />
        <p>Event validation enabled </p>   
        <asp:Button runat="server" ID="btnSave" Text="Save" /> 
        | <asp:Label runat="server" ID="lblLstPostBackTime" />
    </form>
</body>
</html>

Generic Handler:
public class GenericHandler : IHttpHandlerIRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        StringBuilder data = new StringBuilder();
        context.Response.ClearHeaders();
        context.Response.ClearContent();
        context.Response.Clear();
        data.Append("[");
        string q = context.Request.QueryString.Get("q");
        switch(q)
        {
            case "countries":
                for (int i = 0; i < 1000; i++)
                    data.AppendFormat("{{\"value\":\"Value{0}\", \"text\":\"Text{0}\"}},", i);
                break;
        }
        data.Append("]");            
        string json = data.ToString();
        if (json.EndsWith(",]")) json = json.Remove(json.Length - 2, 1);
        context.Response.ContentType = "application/json";
        context.Response.ContentEncoding = Encoding.UTF8;
        context.Response.Write(json);
        context.Response.Flush();
        context.ApplicationInstance.CompleteRequest();
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Sunday, August 29, 2010

How to remove asp.net menu item using java script and jQuery

<%@ Page Language="C#" %>
<html>
<head id="Head1" runat="server">
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script language="javascript">
        $(document).ready(function () {
            $(".Hide").parent().remove();
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div class="Container">
        <asp:SiteMapDataSource runat="server" ID="smdDataSource" ShowStartingNode="false" />
        <asp:Menu runat="server" ID="menuItems" DataSourceID="smdDataSource">
            <DynamicItemTemplate>
                <asp:HyperLink runat="server" ID="menuLink" 
                    Text='<%# Eval("Text") %>' 
                    NavigateUrl='<%# Eval("NavigateUrl") %>'                          
                    CssClass='<%# (Eval("NavigateUrl").ToString()).Contains("HiddenPage.aspx")? "Hide" : "Normal" %>'
                 />
            </DynamicItemTemplate>
        </asp:Menu>
    </div>
    </form>
</body>
</html>

Wednesday, August 25, 2010

How to update small portion of a website using jQuery and ajax

We can use Generic Hanlder to render the response for the ajax request.
Example

Page
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head2" runat="server">
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
            function UpdateTime() {                
                $.ajax({
                    url: "GenericHandler.ashx",
                    success: function (data) {
                        $(".LabelTime").text(data);
                    }
                });
            }
 
            $(document).ready(function () {
                setInterval('UpdateTime()', 3000);
            });
    </script>
    <script runat="server">        
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.lblTime.Text = DateTime.Now.ToString("hh:mm:ss");
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Label runat="server" ID="lblTime" CssClass="LabelTime" />
    </form>
</body>
</html>
GenericHandler.ashx
public class GenericHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {            
        context.Response.Write(DateTime.Now.ToString("hh:mm:ss"));
        context.Response.Flush();
        context.Response.End();
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Friday, August 20, 2010

How to encode html in client side and benefit from request validation in asp.net in a case of html text input

It is common issue to have request validation failure while having HTML input in form inputs (TextBoxes). So easiest and widely used approach is to turn off request validation in the page to accept html input and encode only the expected control text. By ignoring other input controls we leave considerable space for attackers to inject some nasty html in to input controls.
So this approach is to have an input control which accepts html text in the page and also have request validation enabled. For this we can encode html in the client side and send only the encoded html to the server to comply with request validation in asp.net


Demo:
Tip: .net framwork validate inputs of asp.net controls only
<input type='text' runat='server id="txtName" /> - get validated
<asp:TextBox runat="server" Id="txtName" /> - get validated
It ignores regular input elements in a the page.
<input type='text '>  - not get validated
I have two side by side input controls one is text input and other is hiden field. From those two only the hidden field represents a .net control. You actually type on non .net control (html input). In the same time when I type it encodes html into hidden field (asp.net control) So even though I post two input controls when I post data one has row html(input element) and one has encoded html (asp.net control) .net framwork identify no risk as .net control (hidden filed) has encorded html. It just ignore the regular text input control with row html.
For a confirmation please see view source after row html postback of the demo page.
Example of use:
<%@ Register Assembly="ActiveTest" Namespace="ActiveTest" TagPrefix="asp" %> 
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head2" runat="server">
    <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
    <script runat="server">
        protected void Save(object sender, EventArgs e)
        {
            string encodedHtml = this.htxtDescrition.Text;
        }
    </script>
</head>
<body>
    <form id="form2" runat="server">
        Description <asp:HtmlTextBox runat="server" ID="htxtDescrition" IsMultiLine="true"  />
        <hr />
        <asp:Button runat="server" ID="Button1" Text="Save" OnClick="Save" />
    </form>
</body>
</html>
Control Implementaion
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class HtmlTextBox : WebControlIPostBackDataHandlerINamingContainer
{
    public string Text
    {
        get { return (string)(ViewState["Text"] ?? (ViewState["Text"] = string.Empty)); }
        set { ViewState["Text"] = value; }
    }
    public int Rows
    {
        get { return (int)(ViewState["Rows"] ?? (ViewState["Rows"] = 10)); }
        set { ViewState["Rows"] = value; }
    }
    public int Colums
    {
        get { return (int)(ViewState["Colums"] ?? (ViewState["Colums"] = 40)); }
        set { ViewState["Colums"] = value; }
    }
    private string controlScript = @"
        function EncodeHtml(soruce) {
            var text = $(""#"" + soruce).val();
            var encodedHtml = $(""<div/>"").text(text).html();
            $(""#"" + soruce + ""Value"").val(encodedHtml);
        }
    ";
    private string instanceScript = @"
        $(document).ready(function () {{
            var controlId = ""#"" + ""{0}"" + ""Value"";
            var text = $(controlId).val();
            var encodedHtml = $(""<div/>"").text(text).html();
            $(controlId).val(encodedHtml);
        }});
    ";
    public bool IsMultiLine { getset; }
    public bool AutoPostBack { getset; }
    public event EventHandler TextChanged;
    public virtual bool LoadPostData(string postDataKey,
                                    NameValueCollection postCollection)
    {
        string postedValue = postCollection[postDataKey];
        this.Text = postedValue;
        return false;
    }
    public virtual void RaisePostDataChangedEvent()
    {
        OnCheckChanged(EventArgs.Empty);
    }
    protected virtual void OnCheckChanged(EventArgs e)
    {
        if (TextChanged != null)
            TextChanged(this, e);
    }
    protected override void Render(HtmlTextWriter output)
    {
        string colsAndRows = this.IsMultiLine ? string.Format(" rows=\"{0}\" cols=\"{1}\"",
            this.Rows, this.Colums) : string.Empty;
        output.Write(string.Format(@"
            <{0} type=""text"" id=""{1}"" {2}{3} 
            onchange=""javascript:EncodeHtml('{1}')""{4}>{5}</{0}>",
            this.IsMultiLine ? "textarea" : "input",
            this.ClientID,
            this.IsMultiLine ? string.Empty : string.Format(" value=\"{0}\""this.Text),
            this.AutoPostBack ?
                string.Format(" onclick=\"javascript:__doPostBack('{0}','');\""this.UniqueID) : string.Empty,
            colsAndRows,
            this.IsMultiLine ? this.Text : string.Empty));
        output.Write(string.Format("<input type='hidden' value='{0}' id='{1}Value' name='{2}' />",
            this.Text,
            this.ClientID,
            this.UniqueID));
    }
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        if (this.Page != null)
        {
            this.Page.ClientScript.RegisterStartupScript(this.GetType(), this.ClientID,
                string.Format(this.instanceScript, this.ClientID), true);
            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
                this.GetType().Name, this.controlScript, true);
        }
    }
}

Thursday, August 19, 2010

How to upload multiple files using custom web control like asp.net DropDownList

‘How to handle multi file upload?’ is a frequently asked a question through the web developing community. There are numerous solutions being published. In this blog I have posted another post to demonstrate how to upload multiple files at the same time using third party plug-in called file uploadify. However this post aims to answer the same question in different approach. Idea is to have a file list control like asp.net DropDownList control. This is a very basic implementation but this code has holes for template.  This example uses JQuery.

Demo:


Page:

Markup:
Mark-up very simple, first we have to register the asp.net control with tag prefix. In this case, this control is hosted in the name space called ActiveTest and in an assembly ActiveTest.dll. Then we can add FileList control as same as we add a DropDownList to the page.
<%@ Page Language="C#" %>
<%@ Register Assembly="ActiveTest" Namespace="ActiveTest" TagPrefix="asp" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head2" runat="server">
    <script type="text/javascript" src="Scripts/jquery-1.4.1.min.js"></script>
</head>
<body>
    <form id="form2" runat="server">
        <asp:FileList runat="server" ID="flFileList" DataNameField="Name" DataIdField="Id" />
        <asp:Button runat="server" ID="Button1" Text="Save" />
    </form>
</body>
</html>
Code
At the end of the section, you will be able to find a class called Document, which I use to DataBind the FileList control. I hold list of Documents in the ViewState for the purpose of demonstration. You might get this from database.  In the page load method, if page is not a postback, I do create an initial list of fake documents and bind it to the file list. Then again in real world this should come from the database or relevant source.
Then the Save event, probably the most important bit that we may consider. Save event happens as a consequence of save button click, please see the mark-up to locate save button.  In the save button I repopulate the document list that I have created in the initial page load. Then I loop through all the items in the FileList. FileList Item (definition can be found at the end of this post) has four major properties.
  1. IsNew - A new file
  2. IsEmpty - User has clicked add more but has not selected a file
  3. IsEdited - User has edited the existing file
  4. IsExisting  - Not edited existing file
Then I check the state of the item. If file is new or edited then we have to save the file.  Then again before I save the file for the safety, I check if the item has a file or not.  At the same time I populate new Document object and add to my document list. If the file is existing file, we don’t have to save the file but of course we have to add the document object created based on existing file to my document list in-order to bind the FileList.
public partial class Test : Page
{
    private List<Document> documents
    {
        get { return ViewState["Documents"as List<Document>; }
        set { ViewState["Documents"] = value; }
    }
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if (!this.IsPostBack)
        {
            documents = new List<Document>();
            for (int i = 0; i < 10; i++)
                documents.Add(new Document() { Name = "Document Title " + i, FileName = "Doc.doc", Id = "Id" + i });
            this.flFileList.DataSoruce = documents;
            this.flFileList.DataBind();
        }
    }
    protected void Save(object sender, EventArgs e)
    {
        this.documents.Clear();
        foreach (FileListItem item in this.flFileList.Items)
        {
            ///
            /// Save files 
            /// Re-Populate items list
            ///
            if (item.IsEdited || item.IsNew)
            {
                Document d = new Document();
                if (item.HasFile)
                {
                    d.Name = item.File.FileName;
                    d.FileName = item.File.PostedFile.FileName;
                    d.Id = item.IsNew ? "Id" + this.flFileList.Items.IndexOf(item) : item.Id;
                    ///
                    /// item.File.PostedFile.SaveAs("pathToSave");
                    ///                            
                }
                this.documents.Add(d);
            }
            else if (item.IsExisting)
                this.documents.Add(new Document() { Name = item.Name, Id = item.Id });
        }
        ///
        /// Databind
        ///
        this.flFileList.DataSoruce = documents;
        this.flFileList.DataBind();
    }
}
 
[Serializable]
public class Document
{
    public string Id { getset; }
    public string Name { getset; }
    public string FileName { getset; }
}

Control Implementation:
FileList control is probably the most important bit of the post. If you in a hurry and need to enjoy the rest of the day, you may use the control implementation as it is, and get the example running. But for the people who are curious it works, I will explain how it works.
  1. Control has a property called MaxFiles. When it does not have initial list of files to display (i.e. fresh file list), control shows only a single file upload and add more button right next to file upload control.
  2. By clicking add new button you will be able to add another file upload input without a postback, so it is quick and will NOT destroy your excising selected files.
  3. You will be able to add more file uploads up to the number you specify in the MaxFiles property. By default MaxFiles is 5.
  4. When you save selected files, and then in the save event if you rebind the list with saved document list, control will show file names in read-only text boxes and edit button next to each text box to edit them.  By clicking edit button textbox and edit button get converted in to file upload control where you may chose a different file as an edit.
  5. Next to existing files there is a empty input field and add more button which behaves exactly same as we discussed in the point 1 and 2.
Private script variable:
Control uses java scripts to show additional file input fields without using postbacks. Script variable holds the script for this. In the runtime we inject couple of values to the script like currentRow which depends on bounded data source and maxRowCount which corresponds to MaxFile.  Then in the control’s pre-render method, we register the this script with the type of FileList control and ClientID as the key so that each FileList control in the page will have separate script.
Private style variable:
File list control specific styles which will get added to the page header. Those who want to control the disabled colour, textbox disabled colour get injected to styles at the runtime and get registered with the page in the pre-render method.
CreateControlHeirarchy() Method:
The CreateControlHeirarchy() method is the master beast which get called in the page init method. In this method execution loops through the existing items and add necessary controls to the control. Please note the ItemTemplate property. Please add more logic here to get this control customized with template. Each row of control will have a designated index and control classes will get appended with index to provide unique css class name so that jQuery can pick them up.
DataBind() Method:
This uses IEnumarable DataSource property. In the DataBind() method, execution loops through each item in the IEnumarable DataSource and it uses reflection to grill through the object and find the values. This reflection uses DataNameField property and DataIdField property to grab values to FileListItem. Then after populating all the file list items corresponds to data source then it call CreateControlHeirarchy() method to regenerate control collection.

[ParseChildren(true)]
[DefaultProperty("ItemCount")]
public class FileList : WebControlINamingContainerIPostBackDataHandler
{
    #region Attributes
 
    private List<FileListItem> items;
    private List<FileListRow> rows = new List<FileListRow>();
    private string script = @"
        var currentRow = {0};
        var maxRowCount = {1};
        function ShowEditFile(index) {{
            $("".FileName"" + index).hide();
            $("".EditButton"" + index).hide();
            $("".FileUpload"" + index).show();
            return false;
        }}
        function ShowAddFile() {{
            $("".FileListRow"" + currentRow).show();
            currentRow++;
            if (currentRow == maxRowCount)
                $("".AddMore"").attr(""disabled"", ""disabled"");            
            return false;            
        }}
    ";
    private string styles = @"
        <style type=""text/css"">
            .FileList .Hide {{ display:none; }}
            .FileList .FileName {{ background-color: {0}; }}        
        </style>
    ";
 
    #endregion
 
    #region Properties
 
    public List<FileListItem> Items { get { return this.items; } }
    public List<FileListRow> Rows { get { return this.rows; } }
    public int MaxFiles { getset; }
    public IEnumerable DataSoruce { getset; }
    public string DataNameField { getset; }
    public string DataIdField { getset; }
    public int ItemCount { getset; }
    public string ReadOnlyColor { getset; }
 
    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateContainer(typeof(FileListRow))]
    public ITemplate ItemTemplate { getset; }
 
    #endregion
 
    #region Constructors
 
    public FileList()
        : base(HtmlTextWriterTag.Div)
    {
        this.Initialize();
    }
    public void Initialize()
    {
        this.MaxFiles = 5;
        this.ReadOnlyColor = "#ccc";
    }
 
    #endregion
 
    #region Methods
 
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        this.CreateControlHeirarchy();
    }
    public void CreateControlHeirarchy()
    {
        this.Controls.Clear();
        this.TrackViewState();
        this.CssClass = string.Format("{0} {1}"this.CssClass, this.GetType().Name).Trim();
        if (this.items != null)
        {
            this.ItemCount = this.items.Count;
            foreach (FileListItem item in this.items)
                this.AddItem(this.items.IndexOf(item), item);
        }
        else
        {
            int itemCount = 0;
            if (int.TryParse(HttpContext.Current.Request.Form[this.UniqueID], out itemCount))
                this.ItemCount = itemCount;
            for (int i = 0; i < this.ItemCount; i++)
                this.AddItem(i, null);
        }
        for (int i = this.ItemCount; i < this.MaxFiles + this.ItemCount; i++)
        {
            FileListRow row = new FileListRow()
            {
                CssClass = string.Format("{0} {0}{1} {2}",
                    typeof(FileListRow).Name,
                    i, i == this.ItemCount ? string.Empty : "Hide").Trim()
            };
            this.Controls.Add(row);
            this.rows.Add(row);
            if (this.ItemTemplate != null)
                this.ItemTemplate.InstantiateIn(row);
            row.Controls.Add(new FileUpload()
            {
                ID = string.Format("FileUpload{0}", i),
                CssClass = string.Format("FileUpload{0}", i)
            });
            row.Controls.Add(new HiddenField()
            {
                ID = string.Format("FileId{0}", i)
            });
        }
        this.Controls.Add(new Button()
        {
            Text = "Add More",
            OnClientClick = "javascript:return ShowAddFile()",
            CssClass = "AddMore"
        });
    }
    private void AddItem(int index, FileListItem item)
    {
        FileListRow row = new FileListRow() { CssClass = typeof(FileListRow).Name };
        this.Controls.Add(row);
        this.rows.Add(row);
        if (this.ItemTemplate != null)
            this.ItemTemplate.InstantiateIn(row);
        TextBox txtFile = new TextBox()
        {
            ID = string.Format("FileName{0}", index),
            CssClass = string.Format("FileName{0} FileName", index)
        };
        if (item != null) txtFile.Text = item.Name;
        txtFile.Attributes.Add("readonly""readonly");
        row.Controls.Add(txtFile);
        row.Controls.Add(new Button()
        {
            Text = "Edit",
            ID = string.Format("EditButton{0}", index),
            CssClass = string.Format("EditButton{0} EditButton", index),
            OnClientClick = string.Format("javascript:return ShowEditFile({0})", index)
        });
        row.Controls.Add(new FileUpload()
        {
            ID = string.Format("FileUpload{0}", index),
            CssClass = string.Format("FileUpload{0} Hide FileUpload", index)
        });
        HiddenField fileId = new HiddenField() { ID = string.Format("FileId{0}", index) };
        if (item != null) fileId.Value = item.Id;
        row.Controls.Add(fileId);
    }
    public override void DataBind()
    {
        base.DataBind();
        this.items = new List<FileListItem>();
        if (this.DataSoruce != null)
        {
            foreach (object item in this.DataSoruce)
            {
                if (!string.IsNullOrEmpty(this.DataNameField))
                {
                    FileListItem i = new FileListItem();
                    string fn = string.Empty;
                    string fi = string.Empty;
                    foreach (PropertyInfo p in item.GetType().GetProperties())
                    {
                        if (p.Name.Equals(this.DataNameField))
                        {
                            fn = (p.GetValue(item, null) ?? string.Empty).ToString();
                            i.Id = i.Name = fn;
                        }
                        if (!string.IsNullOrEmpty(this.DataIdField) && p.Name.Equals(this.DataIdField))
                        {
                            fi = (p.GetValue(item, null) ?? string.Empty).ToString();
                            i.Id = string.IsNullOrEmpty(fi) ? fn : fi;
                        }
                    }
                    this.items.Add(i);
                }
                else
                {
                    string value = (item ?? string.Empty).ToString();
                    this.items.Add(new FileListItem() { Name = value, Id = value });
                }
            }
        }
        this.CreateControlHeirarchy();
    }
    protected override void RenderContents(HtmlTextWriter writer)
    {
        base.RenderContents(writer);
        writer.Write("<input type=\'Hidden\' value=\'{0}\' id=\'{1}\' name=\'{2}\' />"this.ItemCount, this.ClientID, this.UniqueID);
    }
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        if (this.Page != null)
        {
            this.Page.ClientScript.RegisterClientScriptBlock(
                this.GetType(),
                this.ClientID,
                string.Format(this.script, this.ItemCount + 1, this.ItemCount + this.MaxFiles),
                true);
            Literal styles = new Literal() { Text = string.Format(this.styles, this.ReadOnlyColor) };
            if (this.Page.Header != null)
                this.Page.Header.Controls.Add(styles);
        }
    }
 
    #endregion
 
    #region IPostBackDataHandler Members
 
    public bool LoadPostData(string postDataKey, NameValueCollection postCollection)
    {
        this.ItemCount = int.Parse(postCollection[postDataKey]);
        this.items = new List<FileListItem>();
        foreach (FileListRow row in this.rows)
        {
            int index = this.rows.IndexOf(row);
            TextBox txtFile = row.FindControl(string.Format("FileName{0}", index)) as TextBox;
            HiddenField hdnId = row.FindControl(string.Format("FileId{0}", index)) as HiddenField;
            FileUpload fuFile = row.FindControl(string.Format("FileUpload{0}", index)) as FileUpload;
            FileListItem item = new FileListItem();
            if (txtFile != null) item.Name = txtFile.Text;
            if (hdnId != null) item.Id = hdnId.Value;
            if (fuFile != null) item.File = fuFile;
            this.items.Add(item);
        }
        return true;
    }
    public void RaisePostDataChangedEvent()
    {
 
    }
 
    #endregion
}


Support Classes:
FileListRow and FileListItem are the two support classes for the FileList control. There are no descriptive logic but solely there are there to provide data structures to the FileList control.
[Serializable]
public class FileListRow : WebControlINamingContainer
{
    public FileListRow()
        : base(HtmlTextWriterTag.Div)
    {
 
    }
}
[Serializable]
public class FileListItem
{
    #region Attributes
 
    private bool hasIdAndName
    {
        get { return !string.IsNullOrEmpty(this.Name) && !string.IsNullOrEmpty(this.Id); }
    }
 
    #endregion
 
    #region Properties
 
    public string Name { getset; }
    public string Id { getset; }
    public FileUpload File { getset; }
    public bool HasFile
    {
        get
        {
            return this.File != null && this.File.HasFile;
        }
    }
    public bool IsEdited
    {
        get { return this.hasIdAndName && this.HasFile; }
    }
    public bool IsNew
    {
        get { return !this.hasIdAndName && this.HasFile; }
    }
    public bool IsEmpty
    {
        get { return !this.hasIdAndName && !this.HasFile; }
    }
    public bool IsExisting
    {
        get { return this.hasIdAndName; }
    }
 
    #endregion
}

Azure Storage Account Types

Defferent Types of Blobs Block blobs store text and binary data. Block blobs are made up of blocks of data that can be managed individually...