Category Archives: .NET

Gridview Model binding with Control attribute as parameter

Asp.Net MVC had enjoyed the benefit of Model binding since its inception. It helped in few things such as

  • UI and data model separation.
  • Unit testing of the data binding method. (great! isn’t it?)

With Asp.Net 4.5, Model binding is now available for Web forms as well. Moreover it is integrated in a seamless manner.

so here we go!

UI Code:

New Gridview has two properties to be noticed.

  • ItemType:
  • It needs a type name that you are binding to. It can be a dll which contains the actual method.

  • SelectMethod:
  • It needs a method which returns an IEnumerable or IQueryable type.

    Similarly we have UpdateMethod which is not covered in this post.

    <asp:DropDownList ID="ddlNameFilter" runat="server" AutoPostBack="true" Width="500px" >
                    <asp:ListItem Value="" Text="-- Select word name starts with --" Selected="True" />
                    <asp:ListItem Value="KE" Text="KE" />
                    <asp:ListItem Value="TE" Text="TE" />
                </asp:DropDownList>
    
    </br></br>
                
             <asp:GridView ID="gvPersons" runat="server" 
                    AllowPaging="True" AutoGenerateColumns="False" PageSize="20"             
                 ItemType="WebFormSamples.Person" SelectMethod="GetPersonList" 
                 OnRowDataBound="gvPersons_RowDataBound"
    
                    OnPageIndexChanging="gvPersons_PageIndexChanging">
                    <Columns>
                        <asp:BoundField DataField="BusinessEntityID" HeaderText="Product"
                            SortExpression="BusinessEntityID" />
                        <asp:BoundField DataField="PersonType" HeaderText="PersonType"
                            ReadOnly="True" SortExpression="PersonType" />
                        <asp:BoundField DataField="FirstName" HeaderText="FirstName"
                            SortExpression="FirstName" />
                        <asp:BoundField DataField="LastName" HeaderText="LastName"
                            SortExpression="LastName" />
                    </Columns>
                    <PagerStyle HorizontalAlign="Right" />
                    <PagerSettings Mode="Numeric" />
                </asp:GridView>
    

    Code Behind:

     
            // ddlNameFIlter is a dropdown which user selects and selected value is passed as parameter to the below //<strong>SelectMethod</strong> of Gridview. 
            public IQueryable<Person> GetPersonList([Control("ddlNameFilter")] string searchName)
            {
                List<Person> persons = new List<Person>();
                if ( string.IsNullOrEmpty(searchName))
                {
                    persons = Person.GetPersonList();
                }
                else
                    persons = Person.GetPersonList().Where(p => p.FirstName.ToLower().StartsWith(searchName.ToLower())).ToList();
    
                return persons.AsQueryable();
            }

    There are few more Value providers introduced in Asp.Net 4.5. [QueryString],[Cookie] are also very useful.

    I hope it helps!

    Advertisements

    GridView with built in CustomPaging – Asp.Net 4.5

    Every web developer hates Gridview ViewState specially when its large in size. Solution to this is to create a custom paging solution. but it was too much of work. You need to Create a custom control and then handling all the combinations of click on page links. Styling of the pager was also not standard.

    Asp.Net 4.5 resolved this by providing a Gridview attribute AllowCustomPaging = “true” which allow us to utilize built in gridview paging with custom paging logic. There is one more property VirtualItemCount added to gridview which should be set to the total number of records.

    Below is the simple example. It seems so easy that you can do it right away in your existing code with minimal changes.

    UI Code:

    
     <asp:GridView ID="gvPersons" runat="server" 
      AllowCustomPaging="true"
      AllowPaging="True"           AutoGenerateColumns="False" PageSize="20"
      OnPageIndexChanging="gvPersons_PageIndexChanging">
    
     <Columns>
     <asp:BoundField DataField="BusinessEntityID" HeaderText="Product"
     SortExpression="BusinessEntityID" />
    
     <asp:BoundField DataField="PersonType" HeaderText="PersonType"
     ReadOnly="True" SortExpression="PersonType" />
    
     <asp:BoundField DataField="FirstName" HeaderText="FirstName"
     SortExpression="FirstName" />
    
     <asp:BoundField DataField="LastName" HeaderText="LastName"
     SortExpression="LastName" />
    
     </Columns>
     <PagerStyle HorizontalAlign="Right" />
     <PagerSettings Mode="Numeric" />
     </asp:GridView>
    
    

    Custom Paging Stored Procedure in Sql server 2012

    This query is the heart of this custom paging logic. Sql Server 2012 provides simply “Awesome” way of writing a very complex query (in earlier versions).

    
    CREATE PROCEDURE usp_GetPersonsPaged
    	@StartRowIndex  int,
    	@MaximumRows	int
    AS
    BEGIN
    	
    	SET NOCOUNT ON;
    	    DECLARE @lastRowIndex int
    		SET @lastRowIndex = (@StartRowIndex + @MaximumRows) - 1;
    		 
    
    	 SELECT   [BusinessEntityID]
    		 ,[PersonType]     
    		 ,[FirstName]     
    		 ,[LastName]  FROM [AdventureWorks2012].Person.Person
    	 ORDER BY BusinessEntityID
    	 OFFSET @StartRowIndex ROWS
    	 FETCH NEXT @lastRowIndex ROWS ONLY;	
    
    END
    
    

    Code Behind:

    Nothing changes here. Only your data access layer method returns Maximum rows equal to page size.

    protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    gvPersons.VirtualItemCount = Person.GetTotalPersonCount() ;
                    BindGrid(0,gvPersons.PageSize);                
                }
            }
    
            private void BindGrid(int pageIndex,int pageSize)
            {            
                gvPersons.DataSource = Person.GetPersonListPaged(pageIndex, gvPersons.PageSize);
                gvPersons.DataBind();
            }
    
            protected void gvPersons_PageIndexChanging(object sender, GridViewPageEventArgs e)
            { 
                gvPersons.PageIndex = e.NewPageIndex;
                BindGrid(gvPersons.PageIndex,gvPersons.PageSize);
            }
    

    Data Access Code:

    you can use AdventureWorks Sample DB for Sql server 2012 to check out performance.

    
    public class Person
        {
            public int BusinessEntityID { get; set; }
    
            public string PersonType { get; set; }
    
            public string FirstName { get; set; }
    
            public string LastName { get; set; }
    
    
            public static List<Person> GetPersonListPaged(int startIndex, int maxPazeSize)
            {
                List<Person> persons = new List<Person> ();
    
                SqlConnection con = new SqlConnection();
                SqlCommand cmd = new SqlCommand();
                try
                {
                    con.ConnectionString = "data source=.\\sqlserver2012;initial catalog=AdventureWorks2012;integrated security=True;";
    
                    cmd.Connection = con;
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    cmd.CommandText = "usp_GetPersonsPaged";
    
                    cmd.Parameters.AddWithValue("StartRowIndex", startIndex);
                    cmd.Parameters.AddWithValue("MaximumRows"  , maxPazeSize);
                    con.Open();
                    
                    SqlDataReader dr;
                    dr = cmd.ExecuteReader();
                    
                    while (dr.Read())
                    {
                        Person p = new Person() {BusinessEntityID=dr.GetInt32(0),PersonType=dr.GetString(1),FirstName=dr.GetString(2),LastName=dr.GetString(3) };
    
                        persons.Add(p);                    
                    }                
                                    
                    con.Close();
                }
                catch (Exception ex)
                {
    
                }
                finally
                {
                    con.Dispose();
                    cmd.Dispose();
                }
    
                return persons;
            }
    
    
    
            public static int GetTotalPersonCount()
            {
                int totalCount = 0;
    
                SqlConnection con = new SqlConnection();
                SqlCommand cmd = new SqlCommand();            
                try
                {
                    con.ConnectionString = "data source=.\\sqlserver2012;initial catalog=AdventureWorks2012;integrated security=True;";
                    
                    cmd.Connection = con;
                    cmd.CommandType = System.Data.CommandType.Text;
                    cmd.CommandText = "select count(1) from [AdventureWorks2012].[Person].[Person];";
                    con.Open();
                    totalCount = (int)cmd.ExecuteScalar();
    
                    con.Close();
                }
                catch (Exception ex)
                {
    
    
                }
                finally
                {
                    con.Dispose();
                    cmd.Dispose();
                }
    
                return totalCount;
            }
        }
    }
    

    I hope it helps!!

    Reading XML using C# Linq – Short and Simple

    Reading an XML has become easier by new Linq to XML queries. It is as simple as querying a List though there are differences in query as per XML structure you are trying to read.

    Here is simple way to parse/read/query an XML file in the following format.

    XML file:

    <?xml version="1.0" encoding="utf-8" ?>
    <Babies>
      <Baby>
        <Name>Aabhas</Name>
        <Gender>M</Gender>
        <Meaning>Feeling</Meaning>
      </Baby>
      <Baby>
        <Name>Balwan</Name>
        <Gender>M</Gender>
        <Meaning>Strong</Meaning>
      </Baby>
      <Baby>
        <Name>Chandra</Name>
        <Gender>M</Gender>
        <Meaning>Moon</Meaning>
      </Baby>
    </Babies>
    

    Below is the C# class representation of XML file

    public class Baby
    {
     public string Name { get; set; }
     public string Meaning { get; set; }
     public string Gender{ get; set; }
    
    }
    

    Below is the C# code to read the nodes and reading it as List

    XDocument xdoc = XDocument.Load(xmlFileName);
    List<Baby> babies = new List<Baby>();
    babies = (from b in xdoc.Descendants("Baby")
    select new Baby() { Name = b.Element("Name").Value, Meaning = b.Element("Meaning").Value ,Gender=b.Element("Gender").Value }
    ).ToList();
    

    Obviously we can apply search filter to the list and do all the possible list operations.
    I did not provide any analysis for performance here as of now but will test and update this post later.

    I hope it helps!

    Jquery – Cross domain script call – No transport error

    I have spent few hours figuring out that why my below code is not working. This piece of code is beeing called from a asp.net website. It is calling a WebApi http service using jquery ajax api.

    $(document).ready(function () {
    $.ajax({
        url: "http://localhost:65209/api/values/SayHello",
        type: "GET",
        success: function (result) { alert(result);  },
        error:   function () { alert('error'); }
    });
    

    The reason was that using ajax I was trying to make a cross domain script call whiich by default will throw an error saying “No Transport”.
    the solution is to introduce one line which was introduced after jquery 1.4.1 version onwards. Just add this line after $(document).ready() itself.

    jQuery.support.cors = true;

    That’s it! the same code works fine for me.

    Note: Even though it works fine for you if you create your own service layer and website is trying to consume it. But there are few public websites  like netflix which does not allow cross domain scripting.

    I hope it helps!

    Intellitracing in Production environment – Tester meets Developer

    Whenever a tester reports an exception in production, our Nosy 🙂 developers easily deny it saying that it works fine in his Dev environment. They can’t (actually donot want to) debug in production due to various reasons. Also, it is difficult to install any software to collect traces or record logs in Production environment. Hence MS came up with IntellitraceCollection standalone collector to record traces in production environment.

    Intellitracing was introduced in VS 2010 ultimate edition. It is sort of historical debugging mechanism. It captures All Asp.Net, Ado.Net  events and Excpetion details like a recording.

    This standalone collector is .cab file which will come with VS 2012 install itself. You can also download it separately.

    Now with VS 2012 Intellitracing feature enables testers a way of recording their test case. Saving it as a .iTrace file and sharing it with Developer who can open it with VS2012 and replay the whole movie :).

    Here are the steps we have to do it in Proudction environment. This is a one time setup. We should not keep it enabled always as .iTrace files grow in size very fast and your production server memory may be an issue. you can turn it ON and OFF as and when needed.

    1. download intellitracecollctor.cab for VS 2012 RC. (Inellitrace collector)

    2. With VS 2012 RC you will get it installed at this location “<VSInstallDirectory>\Common7\IDE\CommonExtensions\Microsoft\IntelliTrace\11.0.0”

    3. Copy this .cab file to a some other location. Then Open powershell. goto location of .cab file. (PS> cd “location of .cab”)

    4. type command ->  expand /f:* IntelliTraceCollection.cab . (mind this ‘.’ it will maintain the folder structure)

    5. create one more folder where you record all your trace files. On this folder give your Apppool identity user full permissions to R/W.

    6. Add windows feature “Windows Powershell Integrated Scripting Environment”. (You may want to restart not mandatory though).

    7. powershell cmd type -> Import-Module <IntelliTraceExecutableDirectory>\Microsoft.VisualStudio.IntelliTrace.PowerShell.dll

    Now Let us say we have a divide by zero exception in prod. Tester finds it and now want to record this experience as a .itrace file.

    Tester may ask prod support(ASM) to start collecting trace files for sometime. remember you can start it and stop it. so lets enable recording of tester’s experience.

    8. powershell type -> Start-IntelliTraceCollection <ApplicationPool> <PathToCollectionPlan.xml> <Path To Folder Where Saving trace>

    9. it will confirm Yes/No input type Y press enter.

    10.Now tester can go and replicate the issue. once the exception is thrown. Stop the recording.

    11.To stop type ->  Stop-IntelliTraceCollection “DefaultAppPool”

    12. Confirm with Y then press Enter.

    13. Go to your log folder. See for the latest timestamp .itrace file.

    14. copy it and share this .itrace file with Developer. It may be pretty big to attach to a bug so share the location.

    15. Developer just needs to double click on it and VS2012 will be launched on his machine. This is how it looks once developer opens it.

    .iTrace file opened with VS 2012

    .iTrace file opened with VS 2012

    16. you will notice Exception data section there. Just look for one of the last exceptions occured. In my example i have got a Divide by zero exception.

    17. double click on that exception and BOOM!! your code is opened and exact line where the exception was thrown is highlighted. See screenshot

    Code highlight

    Code highlight

    Note: If start command doesnt’ work. Try to import the dll first (point 7).

    Now how cool is that? 🙂

    I am still digging more into it and as soon as i find some more information i will update this post. 🙂

    Update: You might be wondering how .iTrace files will the .pdb location.Actually it can be saved in Symbol Servers which are tracked by these .iTrace files and it opens those debug session from that location from any machine.

    I hope it helps!