Aug292008

No layer web app

As i mentioned in my last posting, i will start writing a small simple web app, and start layering it in each iteration. First iteration is no layer :) web app, i have a database, a web page that displays the the wines in the database with a custom pagination.

below is my simple aspx page

[code:html]

<div>
        <asp:GridView ID="gridWines" runat="server" AllowPaging="True"
            AutoGenerateSelectButton="True" BackColor="LightGoldenrodYellow"
            BorderColor="Tan" BorderWidth="1px" CellPadding="2" ForeColor="Black"
            GridLines="None" PageSize="5">
            <FooterStyle BackColor="Tan" />
            <PagerStyle BackColor="PaleGoldenrod" ForeColor="DarkSlateBlue"
                HorizontalAlign="Center" />
            <SelectedRowStyle BackColor="DarkSlateBlue" ForeColor="GhostWhite" />
            <HeaderStyle BackColor="Tan" Font-Bold="True" />
            <AlternatingRowStyle BackColor="PaleGoldenrod" />
        </asp:GridView>
        <asp:DropDownList ID="listPages" runat="server" AutoPostBack="True"
            onselectedindexchanged="listPages_SelectedIndexChanged">
        </asp:DropDownList>
    </div>
[/code]

Nothing fancy, a gridview with autogenerate columns, and a dropdownllist for pagination. So in the code behind what i need is:

  1.  A function that will return the records with some pagination helping.
  2. a function that will fill the dropdownlist

No thought is spent on the code behind file, as we will be refactoring this code. I added a linq to sql class, and drop all my tables in the database to orm form. The name of the generated datacontext is WineryDataContext, so below is my first function that will get the records from the database.

[code:c#]

private void BindWineGrid(int SkipNumberofRecords,int TakeNumberofRecords)
    {
        WineryDataContext db = new WineryDataContext();
      
        var wineList = (from w in db.Wines
                        orderby w.BottlePrice descending
                        select w).Skip(SkipNumberofRecords).Take(TakeNumberofRecords);
        gridWines.DataSource = wineList;
        gridWines.DataBind();
    }

[/code]

So the code is basically creating an instance of the datacontext, querying the database with skipping records and taking some other records to help pagination, and binding the result to the gridview. The next function will return the number of records in the database to help our pagination, here it is :

[code:c#]

private int TotalWineRecord()
    {
        WineryDataContext db = new WineryDataContext();
        var totalWine = (from w in db.Wines
                         select w.WineID).Count();
        return totalWine;
    }

[/code]

Again nothing fancy, is return number of records. the third  function will fill the dropdownlist with the number of available pages, so user can paginate using this dropdownlist  Here it is :

[code:c#]

private void FillPagination()
    {
        listPages.Items.Clear();
        int TotalRecords = TotalWineRecord();
        int PageCount = TotalRecords%gridWines.PageSize == 0 ? TotalRecords/gridWines.PageSize : TotalRecords/gridWines.PageSize + 1;
        for(int i=1;i<=PageCount;i++)
            listPages.Items.Add(i.ToString());
    }

[/code]

Now that we have almost all our functions, next step is writing to code for dropdownlist selected index changing, this event will fire when the user select a page from the dropdownlist.

[code:c#]

protected void listPages_SelectedIndexChanged(object sender, EventArgs e)
    {
        int PageNo = int.Parse(listPages.SelectedValue);
        int SkippingRecords = PageNo - 1;
        BindWineGrid(SkippingRecords * gridWines.PageSize, gridWines.PageSize);
    }
[/code]

simple ehh?

Last function is page_load:

[code:c#]

protected void Page_Load(object sender, EventArgs e)
    {
        if(!IsPostBack)
        {
            BindWineGrid(0,gridWines.PageSize);
            FillPagination();
        }
    }
[/code]

The above code is perfectly working, so what is wrong with it? First of all there is no layers and seperation of concerns, but why do we need that? Himm even without seperating the layers, the application needs a few refactoring especially to help unit testing. So here are some problems we might have later:

  • if you have another page using wines listing, you will write the same code again
  • database accessing function also touches the ui (gridview filling), so not easy to write unit test
  • if you want to implement business rules (such as drop the very expensive wines from the list), you need repeat your code in every page
  • if your db schema changes you have to change every in every page 
  • your application is not scalable 

there is more and more stuff that you can add here so next step is little bit refactoring.

cheers



Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Aug282008

Layering Apps

I am sure you've heard a lot about layering your application for scalability, maintanence or testing purposes. How do you know you have layered it enough? If you have a ui layer (presentation layer), a database access layer and a business layer, can you say you have 3 tier application?

I am refactoring my old codes, and most of the time i am ashamed of myself having those ugly code no matter what my excuse was (mostly it is either lack of time, or learning curve of new technology). So back to the topic, when you have a class library for db access, a class library business logic, and ui app (either a web app, or desktop app etc), are you 3 layered? By looking my old code, i can answer for myself; NO.

I kinda developed some checkpoints for myself to prove if i am even close enough to writing 3-tier apps. One of the questions in the list is, if my ui is accessing a database, and if by keeping the schema same, i want to switch to an xml file or another database, would i change any code in my ui ? If yes, then still my ui is tightly depending on the database itself more than the domain. Same question applies to business layer, if i change the data souce to an xml file, would it still work without cde changes?

I recently start studying LINQ, so i try to refactor code benefitting linq, but then the same question came to my mind? how will i make 3-tier app with linq? i decided spend more time on this, and i will share my experience about this study here on my blog.  I am going to write a very simple web app using vertigo's coho winery database. I will first start doing 1 tier app :), adding layers as i iterate to new versions, and also refactoring some of code, as i study linq more :)

the database diagram for the application is below:

 


so my next posting will have a simple asp.net page listing info about wines in a gridview


Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Aug222008

LINQ many to many relation

I started studying LINQ as we finally convinced our web master to install framework 3.5 to the web server. LINQ is not that easy when it comes to performance issues, and it is also kinda suprising for me that linq to sql does not directly support many-2-many relation. I have a project that i am working on, having lots of tables in the database. A simplified table structure is below where you can see a many-2-many relation between websites, colleges and divisions. So now i have to write a query that will get info from websites tables, as well as i should get the college and division names for that sites.

 

The first thing i did is to create a partial class, and inside the partial class add functions such as: 

[code:c#]
public College GetSiteCollege()
    {
        WebsitesDataContext db = new WebsitesDataContext();
        WebSiteCollege websiteCollege = this.WebSiteColleges.FirstOrDefault(c => c.WebsiteID == this.ID);
        College college = (from c in db.Colleges
                           where c.ID == websiteCollege.CollegeID
                           select c).SingleOrDefault();
        return college;
    }

    public Division GetSiteDivision()
    {
        WebsitesDataContext db = new WebsitesDataContext();
        WebSiteDivision webSiteDivision = this.WebSiteDivisions.FirstOrDefault(c => c.WebSiteID == this.ID);
        Division division = (from d in db.Divisions
                             where d.ID == webSiteDivision.DivisionID
                             select d).SingleOrDefault();
        return division;
    }

[/code]

So now, when i need to bind the websites to a gridview, and lets say, the grid needs the colleges and divisions information for a site, the binding query has to call these functions for each row, which will end up querying the database #(websites) X (#(colleges)+#(divisions)) where # represents "Number of". As you can guess this is lots of query. So the next thing i did is to look for a good join :) to simply the database query. I havent found so many stuff about many-2-many relations with linq, so below is my code that i wrote, and i profiled this code, linq makes only 2 queries this time :) great...

[code:c#]

WebsitesDataContext db = new WebsitesDataContext();
        var webSitesData = from w in db.Websites
                           join c in db.Colleges on
                               w.WebSiteColleges.SingleOrDefault(x => x.WebsiteID == w.ID).CollegeID
                               equals c.ID
                           join d in db.Divisions on
                               w.WebSiteDivisions.SingleOrDefault(y => y.WebSiteID == w.ID).DivisionID
                               equals d.ID
                           select new
                                      {
                                          ID = w.ID,
                                          SiteName = w.SiteName,
                                          SiteUrl = w.SiteUrl,
                                          CollegeAbbr = c.Abbr,
                                          DivisionAbbr = d.Abbr
                                      };
[/code]



Tags: ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Aug112008

Response.Redirect throws an exception?!!

One of my collegue asked my help today about his login page throwing an exception. He is using membership provider to authenicate the users however he is not using role provider. In the login page code behind file, he authenticates the user, and checks the user's role and Response.Redirect to a new  page depending on the role. (Dont ask me why not role provider?). A sample code is :

[code:c#]

   try{
        if(User.IsInRole("guest")
             Response.Redirect("/guest.aspx");
       else if(User.IsInRole("member")
             ....
      }
     catch{
     .....
}

[/code]

Now that the above code is always throwing an exception, i googled it, and found out that Response.Redirect(url,bool end) , the second parameter means end the current thread if it is true. By default it is true, which means kill the thread and redirect to url, however, the code is in a try catch block, which wont simply kill the thread, and will throw an exception. The easiest solution will be changing true to false; however i am not suer about the performance when you let the current thread run to finish and navigate to the second page. So i recommended him removing try catch :)



Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses