Click here to Skip to main content
15,895,011 members
Articles / Web Development / ASP.NET

Web Application Page Patterns

Rate me:
Please Sign up or sign in to vote.
4.47/5 (4 votes)
23 Jan 200710 min read 47.2K   349   53  
Two common design patterns for web application pages: the Single Entity Postback Editor and the Multi-Entity Postback Editor
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

//supporting ORM framework
using WebAppPatterns.Bizlayer;
using MyGeneration.dOOdads;



public partial class OrderEditor : PostbackEditor
{

	const string DETAIL_QUANTITY_CTLNAME = "prodqty_";
	private OrderDetail _orderDetails = new OrderDetail();

	public OrderDetail MyOrderDetails
	{
		get { return _orderDetails; }
		set { _orderDetails = value; }
	}
	

	/// <summary>
	/// New load event must override load in the PostbackEditor base page
	/// and call that method to invoke the required functionality.
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="e"></param>
	override protected void Page_Load(object sender, EventArgs e)
	{
		System.Diagnostics.Debug.WriteLine("Begin Loading Order");
		base.Page_Load(sender, e);
	}

	/// <summary>
	/// Adds the customers to the Select.
	/// </summary>
	/// <remarks>
	/// Make sure to always clear your server controls, otherwise they add-on between postbacks.
	/// </remarks>
	private void LoadCustomerSelect()
	{
		selCustomerId.Items.Clear();

		Customer customers = new Customer();
		customers.LoadAll();
		if (!customers.EOF)
		{
			do
			{
				selCustomerId.Items.Add(new ListItem(customers.Name, customers.CustomerID.ToString()));
			} while (customers.MoveNext());
		}
	}

	/// <summary>
	/// We only allow new orders, so this method is left blank.
	/// </summary>
	protected override void LoadEntityIntoForm()
	{
		LoadProductList();
		LoadCustomerSelect();
	}

	/// <summary>
	/// Load the entered values into our AnOrder entity object
	/// </summary>
	/// <remarks>
	/// In this method we set the top level values and create the sub-items.
	/// During the save we'll have to populate the foreign key values of
	/// our sub-items
	/// </remarks>
	protected override void LoadFormValuesIntoEntity()
	{
		AnOrder order = (AnOrder)MyEditingEntity;
		
		//Get the posted customer ID from the Request.Forms collection.
		//This circumvents databinding sequence problems found with normal postback controls.
		order.CustomerID = Convert.ToInt32(Request.Form["selCustomerId"]);

		//Now cycle the form and look for our known values, extracting the ID
		//from the name
		string[] formKeys = Request.Form.AllKeys;
		int pos;
		for (int i = 0; i < formKeys.Length; i++)
		{
			//If we find our marker in the name, extract the id 
			//and create a new detail entry
			pos = formKeys[i].IndexOf(DETAIL_QUANTITY_CTLNAME);
			if (pos > -1)
			{
				int prodId = 0;
				if (Int32.TryParse(formKeys[i].Substring((pos + DETAIL_QUANTITY_CTLNAME.Length) ), out prodId))
				{
					//next loop if empty
					if (Request.Form[formKeys[i]].Length == 0) continue;

					int qty = 0;
					Int32.TryParse(Request.Form[formKeys[i]], out qty);
					if (qty > 0)
					{
						MyOrderDetails.AddNew();
						MyOrderDetails.ProductID = prodId;
						MyOrderDetails.Quantity = qty;
					}
				}
			}

		}

	}

	/// <summary>
	/// Save the values back to the database.
	/// </summary>
	/// <remarks>
	/// Because of how MyGeneration dOOdads work, we have to
	/// loop thru the details after saving the main item to apply
	/// our new ID.
	/// </remarks>
	/// <returns></returns>
	protected override bool Save()
	{
		AnOrder order = (AnOrder)MyEditingEntity;
		order.Save();
		int orderId = order.OrderID;

		string orderDetails = "<br/>ID: " + orderId.ToString();

		// In a re-edit scenario, you would either delete and recreate
		// all records, or you would perform a differential comparison and
		// individually add or remove any records
		// PSEUDOCODE:
		// if(!order.IsNew()){
		//    order.ClearAllDetails();
		// }

		//rewind, apply our new orderID, and save
		MyOrderDetails.Rewind();
		do
		{
			MyOrderDetails.OrderID = orderId;
			//for our display
			orderDetails += "<br/>\nGot " + MyOrderDetails.Quantity.ToString() + " of product " + MyOrderDetails.ProductID.ToString();
		} while (MyOrderDetails.MoveNext());

		//dOOdads perform a batch save since they are an abstraction
		//on top of a data table
		MyOrderDetails.Save();

		lblResult.Text = "Saved New Order:" + orderDetails;
		return true;
	}

	private void LoadProductList()
	{
		Product prod = new Product();
		prod.LoadAll();
		string list = "";
		do
			list += BuildProductTableRow(prod);
		while (prod.MoveNext());
		this.phProductList.Controls.Add(
			new LiteralControl(list));
	}

	/// <summary>
	/// Build the editable product row
	/// </summary>
	/// <param name="product"></param>
	/// <returns></returns>
	string BuildProductTableRow(Product product)
	{
		string str = "<tr><td>"
			+ product.Name + "</td><td>" + product.Price.ToString("C") + "</td>\n"
			+ "<td>\n"
			+ "<input type=\"text\" size=\"5\" name=\"" + DETAIL_QUANTITY_CTLNAME + product.ProductID.ToString() + "\" >\n"
			+ "<td>\n"
			+ "</tr>\n";

		return str;
	}
	


	#region Lazy Load methods

	/// <summary>
	/// Loads the entity object based on page record id
	/// </summary>
	/// <returns></returns>
	protected override object LazyLoadEntity()
	{
		AnOrder entityObj = new AnOrder();
		entityObj.LoadByPrimaryKey(this.RecordID);
		if (entityObj.EOF)
		{
			entityObj.AddNew();
			entityObj.OrderID = 0;
		}
		return entityObj;
	}

	/// <summary>
	/// Load factory class.  dOOdads utilize an integrated entity/factory object,
	/// so this also points to a Customer
	/// </summary>
	/// <returns></returns>
	protected override object LazyLoadFactory()
	{
		return new Customer();
	}
	#endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Milliman
United States United States
I have been involved in professional software development for over 15 years, focusing on distributed applications on both Microsoft and Java platforms.

I also like long walks on the beach and a sense of humor and don't like mean people Wink | ;-)

Comments and Discussions