Adding Dynamic Data to Web Forms


Web forms are dynamic Web pages that are compiled on the server and that return HTML code to the requesting client Web browser. Several Web forms with controls and dynamic content that interact with a user make up a Web application. Web forms are divided into two separate code entities: presentation code and functional code. The presentation code implements the visual aspect of a Web form, such as where text, images, and controls are placed within a form and how they are formatted. The functional code implements the functional aspect of the Web form, such as how controls interact with the user and each other. Understanding both code entities is essential to building successful .NET enterprise applications.

Exposing the Business Facade Project

The Visual C# Simple Distributed Application solution created in Chapter 1, "Introducing .NET and Enterprise Architecture," includes a Business Facade project. The purpose of the Business Facade project is to abstract the underlying business and data services. The presentation layer of an application should not include any references to the Data Access, System Frameworks, or any business process- related projects. Rather, the presentation layer should only reference the Business Rules and Business Facade projects. Applications need to access the Business Rules project to access the business objects definitions. Applications need to access the Business Facade project to access the underlying data, system, and business services.

The reason for the abstraction via the Business Facade project is two-fold. First, insulating the application from its implementation allows for greater flexibility in changes. Significant changes to the Data Access component can occur without significant impact to the application. Of course, there are limitations. Renaming or drastically changing data structures used in data binding operations will break application functionality. However, low-level changes to the database and table structure in most cases will not impact the application. Another reason for such abstraction is application flexibility. Keeping the Business Facade project presentation agnostic allows for easy migration to different applications. Desktop and mobile applications can access underlying services just as easily as Web applications. To accomplish this, it is important to not include any presentation-specific information in the Business Facade project, including references to a Web session or Registry settings.

The IssueTracker application implements three classes that serve as middle ground between the application and the underlying functionality: IssueManager, UserManager, and ReferenceDataManager.

The IssueManager class is a simple interface that prevents the application ” whether it is a Web, desktop, or mobile application ”from knowing where the Issue data resides initially. It simply provides methods to get one or more Issue objects or to save a new Issue object. The IssueManager class includes the necessary namespace references to the Data Access project and interacts with the BusinessObjectManager to get or set data. Listing 7-3 shows the implementation of the IssueManager class and its member methods. All methods interact with the BusinessObjectManager, which sets and gets data from the database with the help of stored procedures.

Listing 7-3: Abstracting Issue Set and Get Functions with the IssueManager Class
start example
 public class IssueManager {     private BusinessObjectManager _ObjectManager = new BusinessObjectManager();     public IssueManager()     {     }     public void SaveIssue( Issue argIssue )     {         _ObjectManager.Insert( argIssue );     }     public Issue GetIssue( int intIssueID )     {              Issue objIssue = new Issue();              _ObjectManager.SelectOne( objIssue, intIssueID );              return objIssue;     }     public IssueCollection GetAllIssues()     {         IssueCollection objIssueCollection = new IssueCollection();         _ObjectManager.SelectAll( objIssueCollection );         return objIssueCollection;     } } 
end example
 

The UserManager class performs a similar task but for the User object. Its only public method, GetUser, takes basic information about a person, validates their credentials, and returns a populated User object. You can change the underlying UserObjectManager class to validate credentials against values in the database rather than within Active Directory. Such a drastic change in implementation has no impact upon the application as long as the User business object was not altered . Listing 7-4 shows the implementation of the UserManager class and its member methods. A single method is exposed, GetUser, that takes a username and a password as parameters, validates them, and returns a populated User object.

Listing 7-4: Abstracting User Set and Get Methods with the UserManager Class
start example
 public class UserManager {     private UserObjectManager _ObjectManager = new UserObjectManager();     public UserManager()     {     }     public User GetUser( string strEmailAddress, string strPassword )     {         User objUser = null;         objUser = _ObjectManager.ValidateLoginWithProfile( strEmailAddress,             strPassword );         return objUser;     } } 
end example
 

Finally, the ReferenceDataManager initializes and exposes parts of the DataComponent object. Three methods expose DataTable structures that are populated by the DataComponent object, making them available for data binding functions. Listing 7-5 shows the implementation of the ReferenceDataManager class. All get methods return DataTables that can be bound between the Web form controls and the DataComponent object.

Listing 7-5: Abstracting Reference Data Retrieval with the ReferenceDataManager Class
start example
 public class ReferenceDataManager {     DataComponent _AppDataComponent;     public ReferenceDataManager()     {         _AppDataComponent = new DataComponent();     }     public DataTable GetIssueTypes()     {         return _AppDataComponent.ReferenceDataSet.Val_IssueType;     }     public DataTable GetPriorities()     {         return _AppDataComponent.ReferenceDataSet.Val_Priority;     }     public DataTable GetStatuses()     {         return _AppDataComponent.ReferenceDataSet.Val_Status;     } } 
end example
 

Applying Standard Data Binding

Data binding is a mechanism within the .NET Framework that enables form fields to establish a connection with any data collection. A form control, such as a DropDownList, can reference a data collection, such as a DataSet object, and auto-populate the control with the values within the collection. This frees the developer from implementing code that first retrieves the values from a collection, iterates through them, and then individually inserts them to the DropDownList control.

Adding Reference Data Binding

Adding data binding to a Web form requires changes to the code-behind page for the Web form. To set the connection between the DropDownList control within the Web form and the reference data, specify the DataSource, DataTextField, and DataValueField properties. Then, invoke the DataBind method to establish the connection. Listing 7-6 shows the code behind the IssueDetails.aspx page. A class member points to the ReferenceDataManager object. Next, the Page_Load method uses that object reference to establish data bindings to three different form controls. For each control, three properties are set. First, the DataSource property points to the data collection. Next , the DataTextField points to display values within the data collection. Finally, the DataValueField property points to the values within the data collection that match the display values. Once all properties are set, the DataBind method triggers the binding process.

Listing 7-6: Binding Web Form Controls to Reference DataTable Objects
start example
 public class IssueDetails : System.Web.UI.Page {     ReferenceDataManager _DataManager = new ReferenceDataManager();     private void Page_Load(object sender, System.EventArgs e)     {         Issue_TypeID.DataSource = _DataManager.GetIssueTypes();         Issue_TypeID.DataTextField = "TypeLabel";         Issue_TypeID.DataValueField = "TypeID";         Issue_StatusID.DataSource = _DataManager.GetStatuses();         Issue_StatusID.DataTextField = "StatusLabel";         Issue_StatusID.DataValueField = "StatusID";         Issue_PriorityID.DataSource = _DataManager.GetPriorities();         Issue_PriorityID.DataTextField = "PriorityLabel";         Issue_PriorityID.DataValueField = "PriorityID";         Page.DataBind();         return;     } } 
end example
 

At runtime, the Web form will initialize and the Page_Load method will establish the data binding. The result is that the three specified DropDownList controls will automatically fill with data from the bound table. Given the relative ease involved in binding list-related controls to data tables, enterprise applications should make the greatest effort to externalize all list data within the database rather than hard-coded within the Web form itself. The result will pay off in terms of greater customization and possible localization.

Adding Application Data Binding

In the case of reference data binding, DropDownList controls were bound to DataTable objects that were populated by the DataAccess project and exposed by the Business Facade project. You can also establish data binding between more complex user interface elements, such as a DataGrid control and a business object collection. In Listing 7-7, the IssueSummary.aspx page populates a DataGrid control with Issue objects retrieved by the BusinessObjectManager class.

Listing 7-7: Data Binding a DataGrid to a Custom Business Object Collection
start example
 public class IssueSummary : System.Web.UI.Page {     protected System.Web.UI.WebControls.DataGrid gridIssues;     private IssueManager _Issues = new IssueManager();     private void Page_Load(object sender, System.EventArgs e)     {         gridIssues.DataSource = _Issues.GetAllIssues();         gridIssues.DataBind();         return;     } } 
end example
 

The Page_Load method populates the DataGrid control with the contents of an object inheriting from the BusinessObjectCollection class. In this case, the control displays all Issue objects stored in the Dat_Issue table. The BusinessObjectCollection class makes this possible because it implements the IEnumerable interface. The only problem remaining is that the DataGrid control is not properly formatted, and all Issue object fields are displayed. The next step is to apply formatting within the form designer. Open the IssueSummary.aspx, select the DataGrid control, and select PropertyBuilder from its context menu. The PropertyBuilder will display. First, select the Columns tab page on the left. Next, uncheck the Create Columns Automatically at Run Time option. Finally, format the DataGrid by adding Bound Column from the Available Columns list to the Selected Columns list. For each column, specify a column header for the grid and a data field from which to load. In Figure 7-7, the first column added is a Bound Column with an Issue ID header label. The actual row data for this column will be pulled from the IssueID property of the business object. You can do more formatting, such as alternating row colors and custom fonts, within the other tab pages.

click to expand
Figure 7-7: Setting DataGrid properties within the form designer

The result is a properly formatted DataGrid control that is bound to a custom business object collection. Figure 7-8 shows the completed IssueSummary.aspx Web form. It has additional formatting, such as row alignment and fonts, to blend with the rest of the Web application.

click to expand
Figure 7-8: Displaying dynamic data in a DataGrid control using data binding

Applying Business Object Reflection

Another option for displaying dynamic data within a Web form is to implement a reflection-based data binding system. This approach works by using reflection methods to examine a specific business object and set form controls with matching IDs. Implementing reflection-based data binding is a two-step process. First, you must implement the functionality that examines a business object and sets control values. Second, you create and modify Web forms to use this functionality.

Creating the Reflection Page

There are many different ways to implement reflection-based data binding. The IssueTracker application implements this in the new object ReflectionPage. ReflectionPage inherits from the System.Web.UI.Page class and is able to easily interact with all child controls placed into any derived child pages.

To begin, add a new class file named ReflectionPage.cs to the WebUI project. The new class file will require a namespace reference to the Business Rules project as well as System.Reflection, System.Web.UI, and System.Web.UI.WebControls. There are three different parts to the ReflectionPage object. First, a private BusinessObject variable serves as the source of reflection data. Second, a property accessor method exposes that business object. Third, the ReflectBusinessObject sets form control values based upon business object values. Listing 7-8 outlines the complete class.

Listing 7-8: Dynamically Populating Web Form Controls Using Reflection
start example
 public class ReflectionPage : System.Web.UI.Page {     private BusinessObject _SourceObject;     public BusinessObject BusinessObject     {         get { return _SourceObject; }         set { _SourceObject = value; }     }     public void ReflectBusinessObject()     {         string strObjectPrefix;         string strObjectValue;         string strFieldName;         Type objType;         Type controlType;         PropertyInfo propObject;         try         {             objType = _SourceObject.GetType();             strObjectPrefix = objType.FullName.Substring(                 objType.FullName.IndexOf(".") + 1 ) + "_";             //iterate through all controls on the page             foreach( Control controlChild in Page.Controls[1].Controls )             {                 if( controlChild.ClientID != null )                 {                     if( controlChild.ClientID.StartsWith( strObjectPrefix ) )                     {                         //get the property value matching the control name                         controlType = controlChild.GetType();                         //get the field name                          strFieldName = controlChild.ClientID.Substring(                              controlChild.ClientID.IndexOf( "_" ) + 1 );                          //get the text value                          propObject = objType.GetProperty( strFieldName );                          strObjectValue = propObject.GetValue( _SourceObject,                              null ).ToString();                          //set the textbox control                          if( controlType.Name.CompareTo( "TextBox" ) == 0 )                          {                               ((TextBox)controlChild).Text = strObjectValue;                          }                          if( controlType.Name.CompareTo( "DropDownList" ) == 0                          {                               ((DropDownList)controlChild).SelectedIndex =                                  int.Parse(strObjectValue);                          }                      }                  }             }         }         catch( Exception x )         {         }         return;     } } 
end example
 

The ReflectBusinessObject method does all of the real work. It begins by retrieving information about the business object ( specifically , its data type). Next, the method iterates through all of the child controls on the Web form. If a form control has a valid ID, then it is examined more closely. The control ID must have a prefix that matches the business object's data type. From there, the control ID suffix tries to match specific attributes defined within the business object. If it finds a match, then it examines the form control's type to set its display value appropriately. TextBox controls have their Text properties assigned while DropDownList controls have their SelectedIndex property assigned.

Note  

Because naming conventions insist that form controls have IDs that match the business object name and attributes, the method runs quickly.Without such naming conventions, this method could also access a collection of business object and study each one until a match is found. The cost would be a tremendous performance impact.

Turning Web Forms into Reflection Pages

Because the ReflectionPage object inherits from the Page object, just as any other Web form does, any new or existing Web form can become a reflected page by simply changing its class definition to inherit from ReflectionPage rather than Page. Listing 7-9 tests the IssueDetails.aspx page by changing the Web form into a reflection page and setting its business object to a test Issue object.

Listing 7-9: Inheriting from ReflectionPage Instead of the Page Base Class
start example
 public class IssueDetails : ReflectionPage //System.Web.UI.Page {     private void Page_Load(object sender, System.EventArgs e)     {         Issue myIssue = new Issue();         myIssue.Summary = "This is test summary text.";         myIssue.Description = "This is a detailed test description.";         myIssue.EntryDate = new DateTime();         myIssue.Priority = 3;         myIssue.TypeID = 3;         BusinessObject = myIssue;         ReflectBusinessObject();     } } 
end example
 

By changing the base class of the Web form to the new ReflectionPage class and specifying a new Issue business object to populate from, the IssueDetails.aspx page renders itself, as shown in Figure 7-9.

click to expand
Figure 7-9: Displaying dynamic Web form data using reflection

There are many approaches for displaying dynamic data in a Web form. Integrated data binding and reflection both have their own advantages. Selecting the appropriate implementation depends upon the purpose of the form.




Developing. NET Enterprise Applications
Developing .NET Enterprise Applications
ISBN: 1590590465
EAN: 2147483647
Year: 2005
Pages: 119

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net