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
<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>
Nothing fancy, a gridview with autogenerate columns, and a dropdownllist for pagination. So in the code behind what i need is:
- A function that will return the records with some pagination helping.
- 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.
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();
}
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 :
private int TotalWineRecord()
{
WineryDataContext db = new WineryDataContext();
var totalWine = (from w in db.Wines
select w.WineID).Count();
return totalWine;
}
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 :
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());
}
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.
protected void listPages_SelectedIndexChanged(object sender, EventArgs e)
{
int PageNo = int.Parse(listPages.SelectedValue);
int SkippingRecords = PageNo - 1;
BindWineGrid(SkippingRecords * gridWines.PageSize, gridWines.PageSize);
}
simple ehh?
Last function is page_load:
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
BindWineGrid(0,gridWines.PageSize);
FillPagination();
}
}
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: