ASP.NET开发B2C电子商务系统

在对ASP.NET Web表单的编程模型有了基本的认识后,通过应用于现实的开发案例来提高对ASP.NET Web表单内在运作机制的了解,以及由此带来的对系统架构的掌控是很有必要的。我们没有为编程而编程的高贵姿态,我们深深懂得能够开发出高效,健壮,强大的应用程序始终是编程的终极。我们下面通过一个完整的BToC电子商务系统的开发流程来展示ASP.NET Web表单是怎样具体搭建面向下一代网络平台的。
这是一个典型的基于B/S(浏览器/服务器) 三层架构的食品,饮料电子商务零售系统——“玉米地零食店”。前端为产品浏览器,为消费者提供浏览/选购商品,下订单购物等各个环节的功能;中间层为销售商的税率,优惠等商务逻辑;后端为与整个零售系统相关的产品,顾客,订单等数据库。我们采用ASP.NET+IIS 5来构建前端和中间层,SQL Server 2000来管理后端数据库,整个系统运行于Windows XP。相关硬件配置只要满足上述软件的基本配置,系统性能便可保证。下面为该网上零售系统的前端界面图示:
在编制Web 表单商业前端和中间层之前,我们有必要对后端数据库做一个简单的介绍。后端数据库 CornfieldGrocer 由4个表组成:产品类别表Categories ,产品细节表 Details ,产品表 Products ,客户信息表Customers。考虑到演示系统的的简洁性,我们没有添加相关的存储过程,视图,规则等,这些在实际的系统的开发中对提高系统的性能是很有必要,尤其是在大数据量的情况下。下面为4个表的字段的图示介绍:
各个表的字段的表义已经相当清楚,我们不在这里赘述。我们下面向大家展示一下整个电子商务零售系统——“玉米地零食店”的物理文件组成及其结构,下图为示意图:
所有的文件位于ASP.NET站点目录CornfieldGrocer下,其中还有Web表单页面用到的图片子目录Images下的文件就不再在这里列出了。
下面我们开始编写前端和中间层代码,为了更清楚地展示Web Form ASP.NET的底层代码构造,我们采用记事本来完成整个代码的编写过程。需要说明的是在真正的工程项目开发实践中,如能借助Visual Studio.Net等可视集成开发工具,开发效率会大大提高。但在ASP.NET代码的底层机制没有谙熟的情况下,笔者强烈建议初期的开发学习不妨放在Windows系统自带的“记事本”这一简单却能够把代码暴露得相当清晰的工具里。
由于篇幅有限,我们不可能将所有的代码都在这里展示给大家。如前所述,web.config为每个站点级的基于XML的配置文件,负责一些ASP.NET的安全认证,编码选择,诊断测试等ASP.NET的配置工作,为浏览器请求ASP.NET Web表单时通过 IIS处理后的第一站。下面为其内容:
<configuration>
<system.web>
<globalization requestEncoding="UTF-8" responseEncoding="UTF-8" />
</system.web>
</configuration>
容易看到这里的配置内容相当简单,仅指定请求/发送的编码为“UTF-8”。我们对此不再赘述。
global.asax文件及其由后端代码文件global.asax.cs编译成的Bin/CornfieldGrocer.dll共同组成该网上零售系统的ASP.NET应用程序定义。我们先来看文件global.asax:
<%@ Application Inherits="CornfieldGrocer.Global" %>
该文件只有一行指示符,它表示ASP.NET应用程序的定义继承自Global类,而Global类正是在global.asax.cs文件中定义:
using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;
namespace CornfieldGrocer
{
public class Global : System.Web.HttpApplication
{
protected void Session_Start(Object sender, EventArgs e)
{
if (Session["ShoppingCart"] == null)
{
Session["ShoppingCart"] = new CornfieldGrocer.OrderList();
}
}
}
}
在Global类里,我们定义了区段(Session)意义下的购物卡(ShoppingCart)——这里采用了C#中的索引器。购物卡的类型为CornfieldGrocer命名空间中的OrderList类,在CornfieldGrocer.cs文件中有定义。我们当然也可以在global.asax文件中用脚本语言的形式将上面两个文件的内容合并起来,但那不是ASP.NET推荐的做法,因为脚本语言的第一次执行还要进行动态编译,这回损失一部分性能,而将CS文件提前编译成dll文件则会降低这种代价——当然这里的编译的意思还是指将CS的源代码文件编译成微软中间语言的过程。其次,页面与后端代码分离的原则易于项目管理,是Visual Studio.NET推荐的工程性的做法。
文件Default.aspx为整个网上零售系统的前端页面HTML代码,Default.aspx.cs为其后端控制Web表单行为的CS代码。由于篇幅关系我们这里不再赘述其HTML代码,实际上从前面给出的前端界面图示,我们可以基本了解Default.aspx的HTML代码结构。Style.css文件为Default.aspx文件的页面样式定义文件,定义一些页面元素的颜色,格式,间距等修饰性的东西,我们也不再多言。下面只向大家展示Default.aspx的页面指示符:
<%@ AutoEventWireup="false" Inherits="CornfieldGrocer.MainForm" %>
我们用“Inherits="CornfieldGrocer.MainForm"”来表示我们的页面继承自MainForm类,这样我们就实现了对ASP.NET Web 表单行为的控制代码与页面显示的HTML的分离。其中“AutoEventWireup="false"”表示页面事件非自动使能——页面事件非自动使能的意思是所有页面事件必须经过用户明确的操作才能触发,由于该属性缺省为“true”表示自动使能,但我们的商业逻辑要求非自动使能,故这里的语句很有必要,否则会引起系统处理的混乱。下面我们来看MainForm类:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace CornfieldGrocer
{
public class MainForm: System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label CurrentCategory;
protected System.Web.UI.WebControls.Label Name;
protected System.Web.UI.WebControls.Label SubTotal;
protected System.Web.UI.WebControls.ImageButton Imagebutton1;
protected System.Web.UI.WebControls.Label Description;
protected System.Web.UI.WebControls.Label Company;
protected System.Web.UI.WebControls.Repeater DetailsListing;
protected System.Web.UI.WebControls.DataList ProductListing;
protected System.Web.UI.WebControls.DataList ShoppingCartList;
protected System.Web.UI.HtmlControls.HtmlSelect CategoryList;
protected System.Web.UI.WebControls.Button btnSelect;
protected System.Web.UI.WebControls.Label Tax;
protected System.Web.UI.WebControls.Label Total;
protected System.Web.UI.WebControls.ImageButton Imagebutton4;
protected System.Web.UI.WebControls.ImageButton Imagebutton5;
protected System.Web.UI.WebControls.ImageButton Imagebutton6;
protected System.Web.UI.HtmlControls.HtmlInputText Qty;
protected System.Web.UI.HtmlControls.HtmlGenericControl CheckoutPanel;
protected System.Web.UI.HtmlControls.HtmlImage SelectedProdPicture;
public MainForm()
{
Page.Init += new System.EventHandler(Page_Init);
}
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
ProductListing.SelectedIndex = 0;
UpdateProducts();
UpdateShoppingCart();
}
}
private void Page_Init(object sender, EventArgs e)
{
InitializeComponent();
}
private void InitializeComponent()
{
this.btnSelect.Click +=
new System.EventHandler(this.CategoryList_Select);
this.ProductListing.SelectedIndexChanged+=
new System.EventHandler(this.ProductListing_Select);
this.Imagebutton1.Click+=
new ImageClickEventHandler(this.AddBtn_Click);
this.Imagebutton4.Click+=
new ImageClickEventHandler(this.Recalculate_Click);
this.Imagebutton6.Click+=
new ImageClickEventHandler(this.ClearCart_Click);
this.Load +=
new System.EventHandler(this.Page_Load);
}
private void CategoryList_Select(Object sender, EventArgs e)
{
CurrentCategory.Text =
CategoryList.Items[CategoryList.SelectedIndex].Text;
UpdateProducts();
}
private void ProductListing_Select(Object sender, EventArgs e)
{
UpdateProducts();
}
private void AddBtn_Click(Object sender, ImageClickEventArgs e)
{
int productID = Int32.Parse
(ProductListing.DataKeys[ProductListing.SelectedIndex].ToString());
InventoryDB market = new InventoryDB();
DataRow product = market.GetProduct(productID);
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);
shoppingCart.Add(new CornfieldGrocer.OrderItem(productID,
(String) product["ProductName"],
Double.Parse(product["UnitPrice"].ToString()), 1));
UpdateShoppingCart();
}
private void Recalculate_Click(Object sender, ImageClickEventArgs e)
{
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);
for (int i=0; i<ShoppingCartList.Items.Count; i++) >
{
HtmlInputText qty =
(HtmlInputText) ShoppingCartList.Items[i].FindControl("Qty");
try
{
shoppingCart[(String) ShoppingCartList.DataKeys[i]].Quantity
= Int32.Parse(qty.Value);
}
catch (Exception)
{
}
}
UpdateShoppingCart();
}
private void ClearCart_Click(Object sender, ImageClickEventArgs e)
{
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);
shoppingCart.ClearCart();
UpdateShoppingCart();
}
void UpdateProducts()
{
InventoryDB market = new InventoryDB();
int categoryID = Int32.Parse
(CategoryList.Items[CategoryList.SelectedIndex].Value);
ProductListing.DataSource =
market.GetProducts(categoryID).DefaultView;
ProductListing.DataBind();
int productID = Int32.Parse
(ProductListing.DataKeys[ProductListing.SelectedIndex].ToString());
DataRow product = market.GetProduct(productID);
Name.Text = product["ProductName"].ToString();
SelectedProdPicture.Src = product["ImagePath"].ToString();
Description.Text = product["ProductDescription"].ToString();
Company.Text = product["Manufacturer"].ToString();
DetailsListing.DataSource =
market.GetProductCalories(productID).DefaultView;
DetailsListing.DataBind();
}
void UpdateShoppingCart()
{
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);
SubTotal.Text = String.Format("{0:C}", shoppingCart.SubTotal);
Tax.Text = String.Format("{0:C}", shoppingCart.Tax);
Total.Text = String.Format("{0:C}", shoppingCart.Total);
ShoppingCartList.DataSource=shoppingCart.Values;
ShoppingCartList.DataBind();
}
}
}
MainForm类中共有11个方法,19个保护域。其中的19个保护域和前面给出的前端界面图示的页面元素相对应,这里不再赘述。11个方法中MainForm()为构建器,其添加了页面初始化事件Page_Init(),这是ASP.NET Web表单最先处理的事件,一般进行一些基础的初始化操作。我们可以看到在Page_Init()中进行了初始化组件InitializeComponent()的操作。Page_Load()事件出现在用户发出请求后,页面装载的时候,在这里一般可做一些商业逻辑初始化方面的操作,比如数据库的连接,购物卡的初始化等。我们这里进行了产品展示UpdateProducts()和购物卡的初始化UpdateShoppingCart()的操作。
其他四个方法分别为产品类别的选择ProductListing_Select(),购买产品的添加AddBtn_Click(),购物卡的重新计算Recalculate_Click(),购物卡的清除ClearCart_Click()都是通过对ASP.NET控件的操作来触发相应的事件完成商业逻辑。上面的代码已经展示的相当清楚,我们不再赘述。
最后我们要向大家说明的是中间层商务逻辑的组件。它由三个类构成:库存数据类InventoryDB,订单项目类OrderItem和订单列表类OrderList。它们共同在文件CornfieldGrocer.cs文件中定义。自解释的编程方式已经它们的结构展示的相当清除,我们下面只给出该文件的CS源代码:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
namespace CornfieldGrocer
{
public class InventoryDB
{
public DataTable GetProducts(int categoryID)
{
SqlConnection sqlConnect= new SqlConnection
("server=(local);database=CornfieldGrocer;Trusted_Connection=yes");
SqlDataAdapter sqlAdapter1 = new SqlDataAdapter
("Select * from Products where categoryid="+categoryID,sqlConnect);
DataSet products = new DataSet();
sqlAdapter1.Fill(products, "products");
return products.Tables[0];
}
public DataRow GetProduct(int productID)
{
SqlConnection sqlConnect= new SqlConnection
("server=(local);database=CornfieldGrocer;Trusted_Connection=yes");
SqlDataAdapter sqlAdapter1 = new SqlDataAdapter
("Select * from Products where productID=" + productID, sqlConnect);
DataSet product = new DataSet();
sqlAdapter1.Fill(product, "product");
return product.Tables[0].Rows[0];
}
public DataTable GetProductCalories(int productID)
{
SqlConnection sqlConnect = new SqlConnection
("server=(local);database=CornfieldGrocer;Trusted_Connection=yes");
SqlDataAdapter sqlAdapter1 = new SqlDataAdapter
("Select * from Details where productID="+productID,sqlConnect);
DataSet details = new DataSet();
sqlAdapter1.Fill(details, "details");
return details.Tables[0];
}
}
public class OrderItem
{
public int productID;
public int quantity;
public String name;
public double price;
public OrderItem(int productID, String name, double price, int quantity)
{
this.productID = productID;
this.quantity = quantity;
this.name = name;
this.price = price;
}
public int ProductID
{
get { return ProductID; }
}
public int Quantity
{
get { return quantity; }
set { quantity=value; }
}
public String Name
{
get { return name; }
}
public double Price
{
get { return price; }
}
public double Total
{
get { return quantity * price; }
}
}
public class OrderList
{
private Hashtable orders = new Hashtable();
private double taxRate = 0.08;
public double SubTotal
{
get
{
if (orders.Count == 0)
return 0.0;
double subTotal = 0;
IEnumerator items = orders.Values.GetEnumerator();
while(items.MoveNext())
{
subTotal += ((OrderItem) items.Current).Price *
((OrderItem) items.Current).Quantity;
}
return subTotal;
}
}
public double TaxRate
{
get { return taxRate; }
set { taxRate = value; }
}
public double Tax
{
get { return SubTotal * taxRate; }
}
public double Total
{
get { return SubTotal * (1 + taxRate); }
}
public ICollection Values {
get {
return orders.Values;
}
}
public OrderItem this[String name] {
get {
return (OrderItem) orders[name];
}
}
public void Add(OrderItem value)
{
if (orders[value.Name] == null) {
orders.Add(value.Name, value);
}
else
{
OrderItem oI = (OrderItem)orders[value.Name];
oI.Quantity = oI.Quantity + 1;
}
}
public void ClearCart() {
orders.Clear();
}
}
}
需要说明的是我们将三个文件CornfieldGrocer.cs,Default.aspx.cs,Global.asax.cs用编译命令“csc /t:library /out:CornfieldGrocer.dll cornfieldgrocer.cs default.aspx.cs global.asax.cs”将它们全部封装在CornfieldGrocer命名空间里,虽然这并不是必须的。上面的编译器输出CornfieldGrocer.dll文件,我们配置该网上零售站点时只需将该文件拷贝到站点根目录中的Bin目录下即可。
到此为止,我们已经完整的向大家展示了利用ASP.NET Web表单建立一个小型的网上交易系统的编码,配置等工作。当然作为演示案例,它还没有真正系统的完善的性能,安全,界面等各个方面的优化考虑和设计。但它向我们展示的ASP.NET Web表单模型却非常典型且底层,大家不防在此基础上通过不断的修改和扩充来开发适合自己的交易系统。比如对于Default.aspx文件中AutoEventWireup="false"如果设置为“true”或去掉这个语句,在运行页面时会出现什么情况?通过这些练习便会不断的加深我们对ASP.NET底层的认识,最后达到游刃有余的把握。实际上技术的学习,尤其是编程,除了一定的兴趣和悟性外,大量代码实例的锻炼也是很有必要的,这本身就是笔者成长的一个过程,也是本文中笔者竭力要给大家展示的。


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=525052

第一章二手交易系统平台 1.1系统总体设计 1.1.1系统组成描述 1.1.2系统结构描述 1.1.3系统主要关系设计 1.1.4P间数据处理层 1.2数据库设计 1.3系统前台设计 1.3.1主要用户自定义控件 1.3.2首页总体设计 1.3.3注册页设计 1.3.4商品信息详细页设计 1.3.5普通商品信息添加页 1.3.6个人发布信息管理 1.3.7数据搜索结果页 1.4系统后台管理设计 1.4.1后台登录设计 1.4.2后台普通商品信息管理 1.4.3后台租用房屋信息管理 1.4.4后台信息分类管理 1.4.5注册用户信息管理 第二章电子购书网站 2.1系统总体设计 2.1.1系统组成描述 2.1.2系统结构描述 2.1.3系统主要模块关系 2.1.4业务逻辑层 2.2系统数据库设计 2.3系统界面层设计 2.3.1首页设计 2.3.2注册登录 2.3.3书籍详细信息页设计 2.3.4购物篮设计 2.3.5购物清单 2.3.6订购状态页 2.3.7缺书籍反馈页 2.3.8用户管理页 2.3.9书籍管理 2.3.10购物订单管理 2.4系统服务Web Service层设计 2.5 B2C网络支付 第三章PoRTAI.企业级门户网站 3.1系统总体设计 3.1.1系统架构描述 3.1-2系统功能模块描述 3.1.3数据库设计 3.1.4门户网站}I擎动作原理 3.1.5配置信息XM[。文件结构分析 3.1.6 XMI。配置文件操作类 3.1.7系统的层次结构 3.2门户网站引擎设计 3.2.1模块排版系统设计 3.2.2模块排版系统代码分析 3.3角色身份认证 3.3.1角色模块控件 3.4外挂自定义系统 3.5门户站点可重用模块 3.6移动模块设计 第四章BBS论坛系统 4.1系统总体设计 4.1.1系统功能 4.1. 2系统框架 4.1. 3系统附加支持模块(IJtility)概述 4.1.4系统模型对应模块(Model)概述 4.1.5业务逻辑模块(Businessl.,ogic)概述 4.1.6数据库访问层模块(SQL,ServerDAI。)概述 4.1.7系统界面模块(Stella)概述 4.2系统数据库设计 4.2.1数据库设计 4.2.2数据库表结构 4.2.3数据库存储过程设计 4.3系统典型控件和界面设计 4.3.1讨论区域版块信息控件 4.3.2论坛版块控件 4.3.3发表帖子控件设计New。Topic.aSCX- 4.3.4论坛首页index.asp设计 4.3.5分论坛theme.aspx设计 4.3.6发新帖界面new’Fopie.aspx设计 4.3.7论坛注册 4.3.8论坛后台 4.3.9论坛配置信息管理config.aspx设计 4.3.10论坛区域版块管理页district.aspx设计 4.3.11小结 第五章大型汽车新闻网站 5.1系统总体设计 5.1.1系统组成描述 5.1.2系统结构描述 5.1.3发布系统主要模块设计 5.1.4系统通用层Common设计 5.1.5系统逻辑层。Model设计 5.1.6系统数据访问层DataAccess设计 5.1.7系统界面层Web设计 5.2系统数据库设计 5.3后台发布系统设计 5.3.1稿件模板设计和管理 5.3.2发布新闻信息编辑并生成静态页 5.3.3批量静态页生成 5.3.4信息分类管理 5.3.5车型信息管理 5.3.6广告管理 5.3.7网站各栏日信息列表页创建 5.3.8网站首页创建 5.4网站前台设计 第六章oA办公自动化公文流转设计 6.1系统总体设计 6.1.1公文流转组成描述 6.1.2公文流转结构描述 6.2系统数据库设计 6.3具体功能设计 6.3.1创建公文流转 6.3.2流转流程列表 6.3.3流转流程图预览 6.3.4公文新发 6.3.5公文审核 6.3.6公文流转监控
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值