Monday, November 26, 2012

Reading XML with Namespace

If your XML contains Namespace information, then following example illustrates as how to read the data

Let’s consider following XML saved as TestResp.xml

This example contains elements and attribute.

<ResponseData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Result xmlns="http://TestInfo.com/GetData">
<Data>
<Id>3260</Id>
<StatusCode>0</StatusCode>
<StatusValue>NA</StatusValue>
<Values>
    <Value Type="A">1</Value>
    <Value Type="B">1</Value>
</Values>
</Data>
</Result>
</ResponseData>

Now, let’s read the info

Dim xmlString As String = ""
If File.Exists("C:\Test\TestResp.xml") Then xmlString = File.ReadAllText("C:\Test\TestResp.xml")
 
If String.IsNullOrEmpty(xmlString) = False Then
    xmlDoc = New Xml.XmlDocument
    xmlDoc.LoadXml(xmlString)
    Dim ns1 As New Xml.XmlNamespaceManager(xmlDoc.NameTable)
    ns1.AddNamespace("t", "http://TestInfo.com/GetData")
 
    If xmlDoc.SelectSingleNode("//t:Result/t:Data/t:Id", ns1) IsNot Nothing AndAlso _
                   IsNumeric(xmlDoc.SelectSingleNode("//t:Result/t:Data/t:Id", ns1).InnerText) Then
        Dim id As String = xmlDoc.SelectSingleNode("//t:Result/t:Data/t:Id", ns1).InnerText
    End If
 
    If xmlDoc.SelectSingleNode("//t:Result/t:Data/t:Values/t:Value", ns1) IsNot Nothing Then
        Dim xmlnodes As Xml.XmlNodeList = xmlDoc.SelectNodes("//t:Result/t:Data/t:Values/t:Value", ns1)
        For Each nod As Xml.XmlNode In xmlnodes
            If nod.Attributes("Type").Value = "A" Then
                Dim valueTypeA As String = nod.InnerText
            End If
        Next
    End If
End If

Saturday, October 06, 2012

Error: The underlying connection was closed

This is one of the most interesting error you may come across specially when using WCF Services. It will give you no detail, just go figure out - The underlying connection was closed: The connection was closed unexpectedly. So what to do? Most likely you have dataset size issue which is going back and forth between different tiers. For the security and performance reasons you should always limit the size. But if you are required to pass big chunk of data, you have to change the size to it’s maximum. So how do we do it?

 

You have to change the configuration on both side (client and service).

 

On the WCF Service side: ensure that you have

 

<dataContractSerializer maxItemsInObjectGraph="2147483647" />

 

2GB is the maximum size you can send data at once using WCF Service, so please be careful, you can adjust to a lower value as needed

 

<behaviors>
       <serviceBehaviors>
          <behavior name="serviceBehavior_Name">             
            <dataContractSerializer maxItemsInObjectGraph="2147483647" />
          </behavior>
       </serviceBehaviors>
</behaviors>

On the Client Side: Make sure that Binding and behavior info are set correctly

e.g. Binding

<binding name="wsHttpEndpoint_ITestService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
         <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
         <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
         <security mode="Message">
           <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
           <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
         </security>
</binding>

Client Behavior

<behaviors>
     <endpointBehaviors>
       <behavior name="endpointBehavior_Common">
         <dataContractSerializer maxItemsInObjectGraph="2147483647" />
       </behavior>
     </endpointBehaviors>
   </behaviors>

Finally, Client where you refer the actual service

<client>
    <endpoint address="http://www.test.com/TestService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint_ITestService" contract="TestService.ITestService" name="wsHttpEndpoint_ITestService"  behaviorConfiguration="endpointBehavior_Common" />            
</client>

This should fix the above problem.

Thursday, September 06, 2012

WCF Diagnostics

Have you seen weird error messages while using WCF Services and unable to figure out easily as what’s going on? Add the following diagnostics configuration in you config file under configuration section, may be at the bottom. It will generate a file named “App_tracelog.svclog”, you can open as XML file and read the info and may be able to trace the problem easily.

<system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
        <listeners>
          <add name="ServiceModelTraceListener"/>
        </listeners>
      </source>
 
      <source name="System.ServiceModel" switchValue="Verbose,ActivityTracing">
        <listeners>
          <add name="ServiceModelTraceListener"/>
        </listeners>
      </source>
      <source name="System.Runtime.Serialization" switchValue="Verbose,ActivityTracing">
        <listeners>
          <add name="ServiceModelTraceListener"/>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add initializeData="App_tracelog.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelTraceListener" traceOutputOptions="Timestamp"/>
    </sharedListeners>
  </system.diagnostics>

The file will be generated on the same level where config file is available. Make sure to either comment or remove this configuration once you resolved the issue else it may impact the performance and use unnecessary disk space.

Monday, April 09, 2012

Abstract Factory Design Pattern

It is one of the highly used Creational Pattern from Gang of Four patterns. It provides a way to encapsulate a group of individual factories that have a common theme. In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interfaces to create the concrete objects that are part of the theme.

 

The client does not know (or care) which concrete objects it gets from each of these internal factories since it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from their general usage.

 

When and where to use it

You may wonder why you want to create objects using another class (called Abstract Factory) rather than calling constructors directly. Here are some reasons:

  1. Constructors are limited in their control over the overall creation process. If an application needs more control, using Factory is best option. E.g. sharing and re-using objects like object caching, or applications that maintain object and type counts.
  2. There are times when the client does not know exactly what type to construct to use. It is easier to code against a base type or an interface and then let a factory make the decision. ADO.NET objects such as DBConnection, DBCommand etc. are the examples.
  3. Constructors don’t communicate their intention very well because they must be named after their class. Having numerous overloaded constructors may make it hard for the developer to decide which constructor to use. Replacing constructors with intention-revealing creation methods are frequently preferred. 

 

Steps to Create Abstract Factory

  1. First Create Abstract Objects Interfaces (e.g. IAbstractProduct1, IAbstractProduct2) – It is like making of group of objects which will implement the set of same interfaces
  2. Create an Abstract Factory Interface (e.g. IAbstractFactory) which defines the Abstract Object Interfaces created in step 1
  3. Ensure actual concrete object (e.g. Product11 , Product12, Product21 and Product22) implements one of the Abstract Object Interface as defined in step1
  4. Finally Create Concrete Factories(e.g. ConcreteFactory1, ConcreteFactory2) which implements Abstract Factory Interface defined in step 2

 

Sample Code

Step 1.

''' <summary>
''' Abstract Product 1 (Group)
''' </summary>
''' <remarks></remarks>
Public Interface IAbstractProduct1
 
End Interface
 
''' <summary>
''' Abstract Product 2 (Group)
''' For example Here Abstract Product 2 Group is using AbtractProduct1 
''' </summary>
Public Interface IAbstractProduct2
    Function Status(ByVal ab1 As IAbstractProduct1) As String
End Interface

 

Step 2.

''' <summary>
''' Highest Level of Abstraction
''' The Abstract Factory
''' It defines two Abstract Product Groups (1 and 2)
''' </summary>
''' <remarks></remarks>
Interface IAbstractFactory
    Function CreateABF1() As IAbstractProduct1
    Function CreateABF2() As IAbstractProduct2
End Interface

 

Step 3.

''' <summary>
''' Product11 is part of AbstractProduct1 Group
''' </summary>
''' <remarks></remarks>
 
Public Class Product11
    Implements IAbstractProduct1
 
End Class
 
Public Class Product12
    Implements IAbstractProduct1
 
End Class
 
Public Class Product21
    Implements IAbstractProduct2
 
    Public Function SendStatus(ab1 As IAbstractProduct1) As String Implements IAbstractProduct2.Status
        Dim msgString As String = Me.GetType().Name & " is using " & CType(ab1, Object).GetType().Name
        Return msgString
    End Function
End Class
 
Public Class Product22
    Implements IAbstractProduct2
 
    Public Function SendStatus(ab1 As IAbstractProduct1) As String Implements IAbstractProduct2.Status
        Dim msgString As String = Me.GetType().Name & " is using " & CType(ab1, Object).GetType().Name
        Return msgString
    End Function
End Class

 

Step 4

''' <summary>
''' Abstract Factory gets implemented using the Concrete Factory
''' These methods finally gets implemented to return the respective product or object
''' </summary>
''' <remarks></remarks>
Public Class ConcreteFactory1
    Implements IAbstractFactory
 
    Public Function CreateABF1() As IAbstractProduct1 Implements IAbstractFactory.CreateABF1
        Return New Product11()
    End Function
 
    Public Function CreateABF2() As IAbstractProduct2 Implements IAbstractFactory.CreateABF2
        Return New Product21()
    End Function
End Class
 
''' <summary>
''' Abstract Factory gets implemented using the Concrete Factory
''' These methods finally gets implemented to return the respective product or object
''' </summary>
''' <remarks></remarks>
 
Public Class ConcreteFactory2
    Implements IAbstractFactory
 
    Public Function CreateABF1() As IAbstractProduct1 Implements IAbstractFactory.CreateABF1
        Return New Product12
    End Function
 
    Public Function CreateABF2() As IAbstractProduct2 Implements IAbstractFactory.CreateABF2
        Return New Product22
    End Function
End Class

 

Client to Test this Design Pattern

'You can use either ConcreateFactory for this test - Using a Windows app client
        'Dim factory As New ConcreteFactory1
        Dim factory As New ConcreteFactory2
        Dim prod1 = factory.CreateABF1
        Dim prod2 = factory.CreateABF2
        MsgBox(prod2.Status(prod1))

Friday, March 23, 2012

Types Of Design Patterns

In Software Development, a design pattern is generally used as a reusable solution to a commonly occurring problem within a given context in software design. A design pattern is a template or format for how to solve a problem that can be used in many different situations. These Patterns are design and interaction of objects, as well as providing a communication platform for elegant and reusable solution.

There are hundreds of Design Patterns available today but the Gang of Four (GoF) - only considered 23 patterns as the foundation patterns. They categorized in three groups. These patterns are not any Language specific.

(For better focus, each pattern is listed in the group as per their uses. The number in bracket indicates the uses in Microsoft.NET on the scale of 1-5, where 5 is the highest.)

A. Creational Patterns: Helps with creating objects. They abstract the instantiation process of objects and thereby help make a system independent of how its objects are created. These patterns have two common things –

  • Hide the concrete classes the system uses to create objects
  • Hide how instances of these classes are created and composed together

Main Creational Patterns:

  1. Abstract Factory(5) - Creates an instance of several families of classes
  2. Factory Method (5)- Creates an instance of several derived classes
  3. Singleton(4) - A class of which only a single instance can exist
  4. Prototype (3)- A fully initialized instance to be copied or cloned
  5. Builder(2) - Separates object construction from its representation

B. Structural Patterns: It deals with how objects can be composed into a larger Structure. It is usually done by either of two ways

  • Object composition – grouping objects together
  • Interface – Using or extending class’s interface and capabilities at runtime

Main Structural Patterns are

  1. Façade (5) - A single class that represents an entire subsystem
  2. Proxy (4) - An object representing another object
  3. Adapter (4)- Match interfaces of different classes
  4. Composite (4) - A tree structure of simple and composite objects
  5. Bridge (3) - Separates an object’s interface from its implementation
  6. Decorator (3) - Add responsibilities to objects dynamically
  7. Flyweight (1) - A fine-grained instance used for efficient sharing

C. Behavioral Patterns: It deals with algorithms, communication and dispatching of responsibilities between objects. By doing so, these patterns increase flexibilities in carrying out this communication. They shift your focus from flow of control to the way objects are interconnected.

Main Behavioral Patterns are

  1. Iterator (5) - Sequentially access the elements of a collection
  2. Observer(5) - A way of notifying change to a number of classes
  3. Strategy (4) - Encapsulates an algorithm inside a class
  4. Command (4)- Encapsulate a command request as an object
  5. State (3)- Alter an object's behavior when its state changes
  6. Template Method (3) - Defer the exact steps of an algorithm to a subclass
  7. Chain of Responsibilities (2) - A way of passing a request between a chain of objects
  8. Mediator (2) - Defines simplified communication between classes
  9. Interpreter (1) - A way to include language elements in a program
  10. Memento (1)- Capture and restore an object's internal state
  11. Visitor (1) - Defines a new operation to a class without change

There is lots of information available on this topic on the internet. Just wanted to summarize the main patterns first and later write an example on highly used Patterns in .NET. A lot more Design Patterns have evolved over the years and after the above core patterns; some of the above patterns were modified and given a new name or mixed with something new. Some of the design patterns are already implemented in .NET and we use on daily basis.

Wednesday, February 01, 2012

GridView Cell click refreshes detail Gridview

You may have used Master and Detail Gridview to show selected row data in detail Gridview. But what if you have to click on selected cell in one Gridview which happen to result filtered result set in another Gridview.

I will be using two Gridview, AJAX, and a tiny client side JavaScript for this requirement. I will further modify the previous example and add new controls for this requirement. Here is the new code which is self explanatory

WebForm1.aspx

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="WebApplication1.WebForm1" %>
 
<!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>Test Multi Header Gridview</title>
 
     <div id="Div1" runat="server">
     <script language="javascript" type="text/javascript">
 
         function ShowGrid(type, value) {
             document.getElementById("<%=txtType.ClientID%>").value = type;
             document.getElementById("<%=txtValue.ClientID%>").value = value;
             document.getElementById("dataInfo").innerHTML = "Selection Type:" + type + ", Value: " + value;       
             document.getElementById("<%=btnShowData.ClientID%>").click();                 
         }
 
    </script>
    </div>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" />
 
    <div id="searchArea" align="center">
        <asp:Button ID="btnGetData" runat="server" Text="Get Data" />
        <br />
          Export Format 
                      <asp:DropDownList ID="ddlExportData" runat="server" CssClass="clsCombo" >
                            <asp:ListItem Value="CSV" Text="CSV"/>
                            <asp:ListItem Value="XLS" Text="Excel"/>
                            <asp:ListItem Value="XML" Text="XML"/>
                        </asp:DropDownList>&nbsp;
                        <asp:Button ID="btnExportData" runat="server" CausesValidation="false" Text="Export Data" />                                                                                             
 
               <div style="width:0;height:0;display:none;visibility:hidden;">
                            <asp:TextBox ID="txtType" runat="server" Width="0" Height="0" />
                            <asp:TextBox ID="txtValue" runat="server" Width="0" Height="0" />                        
                            <asp:Button ID="btnShowData" runat="server" Width="0" Height="0" />                                                                                                              
               </div>
    </div>
 
    <div align="center">
 
      <asp:GridView ID="gvwRecord" runat="server"  AutoGenerateColumns="false" FooterStyle-Wrap="false" 
                            EmptyDataText="No data is available for this search criteria." DataKeyNames="ID" AllowPaging="false"   > 
             <Columns>                                                                                                   
                <asp:BoundField DataField="ID" HeaderText="ID" ItemStyle-HorizontalAlign="left"/> 
                <asp:BoundField DataField="Name" HeaderText="Name"  ItemStyle-HorizontalAlign="left" ItemStyle-Wrap="false" /> 
                 <asp:TemplateField HeaderText="Age" ItemStyle-HorizontalAlign="Right" HeaderStyle-HorizontalAlign="Center" >
                    <ItemTemplate>
                        <asp:HyperLink ID="hplAge" NavigateUrl="#"  runat="server" Text='<%# Eval("Age")%>' /> 
                    </ItemTemplate>
                </asp:TemplateField>                
                <asp:TemplateField HeaderText="Sex" ItemStyle-HorizontalAlign="Right" HeaderStyle-HorizontalAlign="Center" >
                    <ItemTemplate>
                        <asp:HyperLink ID="hplSex" NavigateUrl="#"  runat="server" Text='<%# Eval("Sex")%>' /> 
                    </ItemTemplate>
                </asp:TemplateField>    
                <asp:BoundField DataField="Title" HeaderText="Title" ItemStyle-Wrap="false"/>                
            </Columns>
        </asp:GridView>
 
 
 
        <br /><br />              
        <b id="dataInfo"></b>  <br />          
        <asp:UpdatePanel ID="UpdatePanelX" runat="server" UpdateMode="Conditional">  
            <ContentTemplate>                                            
            <asp:GridView ID="gvwRecordDetail" runat="server"  AutoGenerateColumns="false" FooterStyle-Wrap="false" 
                            EmptyDataText="No data is available" DataKeyNames="ID" AllowPaging="false"   > 
                <Columns>                                                                                                   
                <asp:BoundField DataField="ID" HeaderText="ID" ItemStyle-HorizontalAlign="left"/> 
                <asp:BoundField DataField="Name" HeaderText="Name"  ItemStyle-HorizontalAlign="left" ItemStyle-Wrap="false" />                                 
                <asp:BoundField DataField="Title" HeaderText="Title" ItemStyle-Wrap="false"/>                
            </Columns>
            </asp:GridView>
                </ContentTemplate>
                <Triggers>               
                    <asp:AsyncPostBackTrigger ControlID="btnShowData" EventName="Click" />                                                                                     
                </Triggers>
       </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

 

WebForm1.aspx.vb

Public Class WebForm1
    Inherits System.Web.UI.Page
 
#Region "Main GridView"
    Protected Sub btnGetData_Click(sender As Object, e As EventArgs) Handles btnGetData.Click
        Dim tst As New TestRecord
        Dim recs As List(Of TestRecord) = tst.LoadData
        Session("Data") = recs
        gvwRecord.DataSource = recs
        gvwRecord.DataBind()
        gvwRecordDetail.Visible = False
 
    End Sub
 
    Private Sub gvwRecord_RowCreated(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvwRecord.RowCreated
        If e.Row.RowType = DataControlRowType.Header Then
            Dim headerCell1 As TableCell = New TableCell()
            Dim headerCell2 As TableCell = New TableCell()
 
            headerCell1.ColumnSpan = 3
            headerCell1.Text = "Main Header 1"
            headerCell1.BackColor = Drawing.Color.LightGray
            headerCell1.HorizontalAlign = HorizontalAlign.Center
 
            headerCell2.ColumnSpan = 2
            headerCell2.Text = "Main Header 2"
            headerCell2.BackColor = Drawing.Color.LightGray
            headerCell2.HorizontalAlign = HorizontalAlign.Center
 
            Dim rowHeader1 As GridViewRow = New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
            rowHeader1.Cells.Add(headerCell1)
            rowHeader1.Cells.Add(headerCell2)
            rowHeader1.ForeColor = Drawing.Color.Black
            rowHeader1.Font.Bold = True
            rowHeader1.Visible = True
            gvwRecord.Controls(0).Controls.AddAt(0, rowHeader1)
 
            Dim fields2 As TableCellCollection = e.Row.Cells
            Dim headerCell11 As TableCell = New TableCell()
            Dim headerCell12 As TableCell = New TableCell()
 
            headerCell11.ColumnSpan = 2
            headerCell11.Text = "ID and Name"
            headerCell11.BackColor = Drawing.Color.Maroon
 
            headerCell12.ColumnSpan = 3
            headerCell12.Text = "Age and Sex"
            headerCell12.BackColor = Drawing.Color.Maroon
 
            Dim rowHeader2 As GridViewRow = New GridViewRow(1, 1, DataControlRowType.Header, DataControlRowState.Normal)
            rowHeader2.Cells.Add(headerCell11)
            rowHeader2.Cells.Add(headerCell12)
 
            rowHeader2.Font.Size = 12
            rowHeader2.ForeColor = Drawing.Color.White
            rowHeader2.HorizontalAlign = HorizontalAlign.Center
            rowHeader2.Visible = True
            rowHeader2.Font.Bold = True
            gvwRecord.Controls(0).Controls.AddAt(1, rowHeader2)
 
        ElseIf e.Row.RowType = DataControlRowType.Footer Then
            Dim footerCell1 As TableCell = New TableCell()
            Dim footerCell2 As TableCell = New TableCell()
            Dim footerCell3 As TableCell = New TableCell()
            Dim footerCell4 As TableCell = New TableCell()
 
            Dim dataRecs As List(Of TestRecord) = Nothing
            Dim totalRec As Integer = 0
            Dim totalMale As Integer = 0
            Dim totalFemale As Integer = 0
            Dim totalAgeBelow30 As Integer = 0
            Dim totalAgeAbove30 As Integer = 0
 
 
            If Session("Data") IsNot Nothing Then
                dataRecs = DirectCast(Session("Data"), List(Of TestRecord))
                If Not dataRecs Is Nothing AndAlso dataRecs.Count > 0 Then
                    totalRec = dataRecs.Count
                    Dim list1 = From r As TestRecord In dataRecs Where r.Sex = "Male"
                    totalMale = list1.Count
 
                    Dim list2 = From r As TestRecord In dataRecs Where r.Sex = "Female"
                    totalFemale = list2.Count
 
                    Dim list3 = From r As TestRecord In dataRecs Where r.Age < 30
                    totalAgeBelow30 = list3.Count
 
                    Dim list4 = From r As TestRecord In dataRecs Where r.Age >= 30
                    totalAgeAbove30 = list4.Count
 
                End If
            End If
 
            footerCell1.Text = "Summary"
            footerCell2.Text = "Age [< 30yrs: " & totalAgeBelow30.ToString() & "] [>=30yrs:" & totalAgeAbove30.ToString() & "]"
            footerCell3.ColumnSpan = 2
            footerCell3.Text = "Male: " & totalMale.ToString() & " Female:" & totalFemale.ToString()
            footerCell4.Text = "Total Count:" & totalRec.ToString()
 
            Dim rowFooter1 As GridViewRow = New GridViewRow(gvwRecord.Rows.Count + 3, 0, DataControlRowType.Footer, DataControlRowState.Normal)
            rowFooter1.Cells.Add(footerCell1)
            rowFooter1.Cells.Add(footerCell2)
            rowFooter1.Cells.Add(footerCell3)
            rowFooter1.Cells.Add(footerCell4)
            rowFooter1.ForeColor = Drawing.Color.Black
            rowFooter1.BackColor = Drawing.Color.LightGray
            rowFooter1.HorizontalAlign = HorizontalAlign.Left
            rowFooter1.Font.Bold = True
            rowFooter1.Visible = True
 
            For cellCount As Integer = 0 To rowFooter1.Cells.Count - 1
                rowFooter1.Cells(cellCount).Wrap = False
            Next
            gvwRecord.Controls(0).Controls.AddAt(gvwRecord.Rows.Count + 3, rowFooter1)
 
        End If
    End Sub
 
    Private Sub gvwRecord_RowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvwRecord.RowDataBound
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim paramString As String = ""
            Dim value As String = ""
 
            value = CType(e.Row.Cells(2).FindControl("hplAge"), HyperLink).Text
            paramString = "javascript:ShowGrid('Age'," & value & ");"
            CType(e.Row.Cells(2).FindControl("hplAge"), HyperLink).Attributes.Add("onclick", paramString)
 
            value = CType(e.Row.Cells(3).FindControl("hplSex"), HyperLink).Text
            paramString = "javascript:ShowGrid('Sex','" & value & "');"
            CType(e.Row.Cells(3).FindControl("hplSex"), HyperLink).Attributes.Add("onclick", paramString)
 
        End If
    End Sub
 
    Private Sub btnShowData_Click(sender As Object, e As System.EventArgs) Handles btnShowData.Click
        Dim typeName As String = Me.txtType.Text
        Dim value As String = Me.txtValue.Text
        Dim testRecs As List(Of TestRecord) = Nothing
        Dim filteredRecs As List(Of TestRecord) = Nothing
 
        testRecs = DirectCast(Session("Data"), List(Of TestRecord))
 
        If typeName = "Age" Then
            Dim recList = From r As TestRecord In testRecs Where r.Age = CInt(value)
            filteredRecs = recList.ToList
        ElseIf typeName = "Sex" Then
            Dim recList = From r As TestRecord In testRecs Where r.Sex.Equals(value)
            filteredRecs = recList.ToList
        End If
 
        Me.gvwRecordDetail.Visible = True
        Me.gvwRecordDetail.DataSource = filteredRecs
        Me.gvwRecordDetail.DataBind()
 
    End Sub
#End Region
 
#Region "Exports"
    Private Sub btnExportData_Click(sender As Object, e As System.EventArgs) Handles btnExportData.Click
        If Me.gvwRecord.Rows.Count > 0 Then
            Select Case Me.ddlExportData.SelectedItem.Value.ToUpper()
                Case "CSV"
                    ExportDataToCSV()
 
                Case "XLS"
                    ExportDataToExcel()
 
                Case "XML"
                    ExportToXML()
            End Select
        Else
            Response.Write("No Data available for export")
        End If
    End Sub
 
    Private Sub ExportDataToCSV()
        Dim fileName As String = "FileName_" & Format(Now, "yyyyMMddhhmms") & ".csv"
        Dim localGridView As GridView = GetLocalMktSourceSummaryGridView()
 
        If localGridView IsNot Nothing AndAlso localGridView.Rows.Count < 65536 Then
            HttpContext.Current.Response.Clear()
            ' Set the response headers to fit our CSV file 
            HttpContext.Current.Response.ContentType = "text/plain"
            HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" & fileName)
 
            Using writer As New System.IO.StreamWriter(HttpContext.Current.Response.OutputStream)
                Dim columnHeader As String = String.Empty
                For i As Integer = 0 To localGridView.Columns.Count - 1
                    columnHeader += localGridView.Columns(i).HeaderText & IIf(i < localGridView.Columns.Count - 1, ",", "").ToString()
                Next
 
                writer.WriteLine(columnHeader)
                'writer.WriteLine(AddCSVHeaderRow()) ' Only if you need custom headers to be added
                ' Add all the data rows 
                For Each row As GridViewRow In localGridView.Rows
                    writer.WriteLine(GetCSVLine(row.Cells))
                Next
            End Using
 
            ' End the current response. Otherwise, excel will open with the whole page inside.
            HttpContext.Current.Response.End()
 
        Else
            Response.Write("Too many rows - Export to Excel not possible")
        End If
 
    End Sub
 
    Private Function GetLocalMktSourceSummaryGridView() As GridView
        Dim rptData As List(Of TestRecord) = Nothing
        Dim localGridView As New GridView
        If Session("Data") IsNot Nothing Then rptData = DirectCast(Session("Data"), List(Of TestRecord))
        localGridView.AllowPaging = False
        localGridView.AllowSorting = False
        localGridView.AutoGenerateColumns = False
 
        localGridView.DataSource = rptData
 
        Dim col01