Three Tier Architecture with ASP.NET...
private void BindOrders() { OrdersBAL bal = new OrdersBAL(); CustomerPortalDAL.OrdersDataTable ordersTable = bal.GetCustomerOrders(((CustomerPortalPageBase)this.Page).SelectedCustomerKey); this.gvwOrders.DataSource = ordersTable; this.gvwOrders.DataBind(); }Figure 1: Binding to an ASP.NET UI Control The example above connects to the business layer to retrieve orders data for a specific customer. This table is bound to a grid, presenting the users with a list of orders for a specified customer. You can see an example of the GridView structure below.
<asp:UpdatePanel ID="upOrders" runat="server" UpdateMode="Conditional"> <ContentTemplate> <asp:GridView ID="gvwOrders" runat="server" AutoGenerateColumns="false" DataKeyNames="OrderKey"> <Columns> <asp:BoundField HeaderText="Order Date" DataField="CreatedDate" DataFormatString="{0:MM/dd/yyyy}" /> <asp:BoundField HeaderText="Total Amount" DataField="TotalAmount" DataFormatString="{0:F2}" /> <asp:BoundField HeaderText="Reference Number" DataField="ReferenceNumber" /> </Columns> <EmptyDataTemplate> No orders have been created for the customer. </EmptyDataTemplate> </asp:GridView> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="btnRefresh" /> </Triggers> </asp:UpdatePanel>Figure 2: GridView Interface Markup The GridView control maps the column structure in the UI to the the collection of orders in the data source. The GridView control is essentially a tabular structure that renders one row for each row in the data source. For example, if there were five orders returned from the business layer, the GridView control renders a header row (using the HeaderText value as the column header), followed by the one row for each of the records in the data table. At a row level, when the first Order is processed, the GridView creates a cell for each of the columns in the Columns definition. It starts out processing the Order Date column, extracting the CreatedDate field from the data row using reflection. This value is inserted into the cell is inserted without any formatting; however, to ensure that only the short-hand version of the date is used, the DataFormatString attribute specifies to use a short-hand form of "month/day/year." Continuing on, the TotalAmount field is extracted from the data source, and passed to the next cell for the column “Total Amount.” The value provided is formatted to a two-digit number using the F2 designation; this ensures only two digits are shown.
protected void gvwOrders_RowUpdating(object sender, GridViewUpdateEventArgs e) { Order order = this.GetOrder((int)gvwOrders.DataKeys[e.RowIndex].Value); GridViewRow row = this.gvwOrders.Rows[e.RowIndex]; order.CreatedDate = DateTime.Parse(((TextBox)row.Cells[0].Controls[0]).Text); order.TotalAmount = decimal.Parse(((TextBox)row.Cells[1].Controls[0]).Text); order.ReferenceNumber = ((TextBox)row.Cells[2].Controls[0]).Text); OrdersBAL bal = new OrdersBAL(); bal.Update(order); this.RefreshGrid(); }Figure 3: Updating an Order In order for this to work, the data needs extracted from the UI controls holding the updated data, which are TextBox controls (which is what the BoundField data field uses). If the UI would have been the TemplateField, a similar approach can still be used here. To delete data, use the following:
protected void gvwOrders_RowDeleting(object sender, GridViewDeleteEventArgs e) { OrdersBAL bal = new OrdersBAL(); bal.DeleteByKey((int)this.gvwOrders.DataKeys[e.RowIndex].Value); This.RefreshGrid(); }Figure 4: Deleting an Order Deleting an order is more simplistic than updating because only the key is needed. If you want to sort or page in the grid, these need handled using the PageIndexChanging and Sorting events as well. If these events are not handled (including the ones handled previous), an exception is thrown because the GridView control does not know what to do in a manual binding situation. Essentially this approach requires the same amount of work as was done in the .NET framework 1.x version with the DataGrid control.
public OrderCollection GetOrders(Customer customer) { }
Figure 5: Method With Business Object – Doesn't Work with ObjectDataSource
Instead, in order for the ObjectDataSource to call this method, it needs the following structure:
public OrderCollection GetOrders(int customerKey) { }Figure 6: Method With Integer – Doesn Work with ObjectDataSource From a user interface standpoint, the UI controls in the .NET framework work well with the DataSourceControl controls. Whenever these UI controls need access to the data, the bound DataSourceControl makes a call to the database, returns the data or performs the correct operation. All of that occurs seamlessly. For example, with the GridView control bound to an ObjectDataSource, whenever it needs to refresh the data, the GridView gets an instance of the underlying bound data source and makes a call to the name of the method specified for the SelectMethod property. To call this method, the ObjectDataSource constructs the business object specified in the TypeName property and invokes the name of the method (defined in SelectMethod) through reflection. Any parameters specified in the SelectParameters collection are passed along to the method as well. These controls can also work with insert, update, and delete operation, as long as all of the parameters are setup correctly. For instance, to setup an ObjectDataSource for these operations and connect to a component, use the following approach:
<asp:ObjectDataSource ID="ods" runat="server" TypeName="Mains.Business.OrdersBAL" SelectMethod="GetOrders" InsertMethod="AddOrder" UpdateMethod="UpdateOrder"> <InsertParameters> <asp:Parameter Name="CreatedDate" Type="DateTime" /> <asp:Parameter Name="TotalAmount" Type="Decimal" /> <asp:Parameter Name="ReferenceNumber" Type="String" /> </InsertParameters> <UpdateParameters> <asp:Parameter Name="CreatedDate" Type="DateTime" /> <asp:Parameter Name="TotalAmount" Type="Decimal" /> <asp:Parameter Name="ReferenceNumber" Type="String" /> </UpdateParameters> </asp: ObjectDataSource >Figure 7: ObjectDataSource Setup In the above example, the select method doesn’t have any parameters, so no parameters are defined. For insert and update operations, each of these methods exposes a signature similar to the one below.
public void InsertOrder(DateTime CreatedDate, decimal TotalAmount, string ReferenceNumber) { .. } public void UpdateOrder(Guid OrderKey, DateTime CreatedDate, decimal TotalAmount, string ReferenceNumber) { .. }Figure 8: Objects Business Layer Setup The difference with UpdateOrder is the key is defined in the DataKeys collection of the Grid. The values are passed from the GridView control and passed to the method through a reflection call. The reflection call assigns the parameters correctly to the method based on matching the parameter names. Some parameter types retrieve their values from an external source; ControlParameter extracts a value from the control it maps to, SessionParameter taps into the Session collection, QueryStringParameter taps into the query collection; etc. Notice my previous implementation used the regular Parameter class; this is sufficient for the GridView. Parameter also has a DefaultValue property that takes a string representing any default value you choose.
<asp:Repeater id="rpt" runat="server"> <ItemTemplate> Name: <asp:Label id="lblName" runat="server" Text='<%# Eval("Name") %>' /> Date: <asp:Label id="lblDate" runat="server" Text='<%# Eval("CreatedDate") %>' /> </ItemTemplate> </asp:Repeater>Figure 9: Repeater Setup As an alternative, some of the other controls take a more simplistic approach to data binding. All that is required is to supply the field that is bound as the text or the value, as shown below:
<asp:DropDownList id="ddl" runat="server" DataSourceID="ods" DataTextField="TotalAmount" DataValueField="OrderKey" />Figure 10: Drop Down List Setup When the source is bound to the DropDownList, a new ListItem is created for each row. The text of the ListItem is supplied from the TotalAmount field, and the value of the ListItem object is supplied from the OrderKey field.