淺析Microsoft .net PetShop程序中的購物車和訂單處理模塊

 

對於Microsoft .net PetShop程序中的購物車和訂單處理模塊,文中主要分析兩種技術的應用:



1. Profile技術在PetShop程序中用於三處:


    1) 購物車ShoppingCart    -下面的例子圍繞購物車流程進行


    2) 收藏WishList


    3)  用戶信息AccountInfo


  註冊新用戶 NewUser.aspx :使用的是CreateUserWizard 控件,基於MemberShip機制,在數據庫MSPetShop4Services的表aspnet_Users中創建用戶


  修改用戶註冊信息 UserProfile.aspx: 基於Profile技術,在數據庫MSPetShop4Profile的表Profiles和Account中創建用戶信息


2. 異步消息處理技術運用於訂單處理



4.1 Web.config配置
Profile可以利用數據庫存儲關於用戶的個性化信息,有點象session對象,但session對象是有生存期的,在生存期後,session對象自動失效了。而profile不同,除非顯式移除它。要實現profile功能,必須先在web.config中進行定義。


在web.congfig中,將會定義一些屬性/值,分別存貯將要保存的變量和值,比如language屬性,定義其值是string類型,如此類推。而<group>標籤,則是將一些相同或類似功能的變量值放在一起。


程序中使用方法:Profile.language = ddlLanguage.SelectedItem.Value;


<profile automaticSaveEnabled="false" defaultProvider="ShoppingCartProvider">


              <providers>


                   <add name="ShoppingCartProvider" connectionStringName="SQLProfileConnString" type="PetShop.Profile.PetShopProfileProvider" applicationName=".NET Pet Shop 4.0"/>


                   <add name="WishListProvider" connectionStringName="SQLProfileConnString" type="PetShop.Profile.PetShopProfileProvider" applicationName=".NET Pet Shop 4.0"/>


                   <add name="AccountInfoProvider" connectionStringName="SQLProfileConnString" type="PetShop.Profile.PetShopProfileProvider" applicationName=".NET Pet Shop 4.0"/>


              </providers>


              <properties>


                   <add name="ShoppingCart" type="PetShop.BLL.Cart" allowAnonymous="true" provider="ShoppingCartProvider"/>


                   <add name="WishList" type="PetShop.BLL.Cart" allowAnonymous="true" provider="WishListProvider"/>


                   <add name="AccountInfo" type="PetShop.Model.AddressInfo" allowAnonymous="false" provider="AccountInfoProvider"/>


              </properties>


         </profile>


 


4.2 購物車程序流程-Profile技術


1. 點擊“加入購物車”: http://localhost:2327/Web/ShoppingCart.aspx?addItem=EST-34


2. ShoppingCart.aspx文件處理:在init方法之前處理


protected void Page_PreInit(object sender, EventArgs e) {


        if (!IsPostBack) {


            string itemId = Request.QueryString["addItem"];


            if (!string.IsNullOrEmpty(itemId)) {


                Profile.ShoppingCart.Add(itemId); //注意ShoppingCart的類型是PetShop.BLL.Cart


                //Save 方法將修改後的配置文件屬性值寫入到數據源,如ShoppingCart屬性已經改變


                Profile.Save();    


         


                // Redirect to prevent duplictations in the cart if user hits "Refresh"


                //防止刷新造成 多次提交


                Response.Redirect("~/ShoppingCart.aspx", true);//將客戶端重定向到新的 URL。指定新的 URL 並指定當前頁的執行是否應終止。


            }


        }


3.     PetShop.BLL.Cart類


// Dictionary: key/value 


private Dictionary<string, CartItemInfo> cartItems = new Dictionary<string, CartItemInfo>();


 


/// <summary>


        /// Add an item to the cart.


        /// When ItemId to be added has already existed, this method will update the quantity instead.


        /// </summary>


        /// <param name="itemId">Item Id of item to add</param>


        public void Add(string itemId) {


CartItemInfo cartItem;


//獲取與指定的鍵相關聯的值TryGetValue(TKey key,out TValue value)


            if (!cartItems.TryGetValue(itemId, out cartItem)) {


                Item item = new Item();


                ItemInfo data = item.GetItem(itemId);


                if (data != null) {


                    CartItemInfo newItem = new CartItemInfo(itemId, data.ProductName, 1, (decimal)data.Price, data.Name, data.CategoryId, data.ProductId);


                    cartItems.Add(itemId, newItem);


                }


            }


            else


                cartItem.Quantity++;


        }


 


4.     更新Profile


//Save 方法將修改後的配置文件屬性值寫入到數據源,如ShoppingCart屬性已經改變


                Profile.Save(); 


如何更新:


    根據配置的ShoppingCartProvider類型 PetShop.Profile.PetShopProfileProvider。


 


ASP.NET 配置文件提供對用戶特定屬性的持久性存儲和檢索。配置文件屬性值和信息按照由 ProfileProvider 實現確定的方式存儲在數據源中。


每個用戶配置文件在數據庫的 Profiles 表中進行唯一標識。該表包含配置文件信息,如應用程序名稱和上次活動日期。


CREATE TABLE Profiles



UniqueID AutoIncrement NOT NULL PRIMARY KEY, 


Username Text (255) NOT NULL, 


ApplicationName Text (255) NOT NULL, 


IsAnonymous YesNo,  


LastActivityDate DateTime, 


LastUpdatedDate DateTime, 


CONSTRAINT PKProfiles UNIQUE (Username, ApplicationName)


)


 


5.     PetShop.Profile. PetShopProfileProvider類, 繼承自ProfileProvider


// 創建 PetShop.SQLProfileDAL.PetShopProfileProvider類-數據庫操作


         private static readonly IPetShopProfileProvider dal


= DataAccess.CreatePetShopProfileProvider();


 


/// <summary>


        /// 設置指定的屬性設置組的值


        /// </summary>


         public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) {


              string username = (string)context["UserName"];


              CheckUserName(username);                        


              bool isAuthenticated = (bool)context["IsAuthenticated"];


 


              int uniqueID = dal.GetUniqueID(username, isAuthenticated, false, ApplicationName);


              if(uniqueID == 0)


                   uniqueID = dal.CreateProfileForUser(username, isAuthenticated, ApplicationName);


 


              foreach(SettingsPropertyValue pv in collection) {


                   if(pv.PropertyValue != null) {


                       switch(pv.Property.Name) {


                            case PROFILE_SHOPPINGCART:   //ShoppingCart


                                 SetCartItems(uniqueID, (Cart)pv.PropertyValue, true);


                                 break;


                            case PROFILE_WISHLIST:


                                 SetCartItems(uniqueID, (Cart)pv.PropertyValue, false);


                                 break;


                            case PROFILE_ACCOUNT:


                                 if(isAuthenticated)


                                     SetAccountInfo(uniqueID, (AddressInfo)pv.PropertyValue);


                                 break;


                            default:


                                 throw new ApplicationException(ERR_INVALID_PARAMETER + " name.");


                       }


                   }


              }


 


              UpdateActivityDates(username, false);


         }


 


// Update cart


         private static void SetCartItems(int uniqueID, Cart cart, bool isShoppingCart) {


              dal.SetCartItems(uniqueID, cart.CartItems, isShoppingCart);


         }


 


6.       PetShop.SQLProfileDAL. PetShopProfileProvider類


使用事務:包含兩個sql動作,先刪除,再插入


/// <summary>


        /// Update shopping cart for current user


        /// </summary>


        /// <param name="uniqueID">User id</param>


        /// <param name="cartItems">Collection of shopping cart items</param>


        /// <param name="isShoppingCart">Shopping cart flag</param>


         public void SetCartItems(int uniqueID, ICollection<CartItemInfo> cartItems, bool isShoppingCart) {


                   string sqlDelete = "DELETE FROM Cart WHERE UniqueID = @UniqueID AND IsShoppingCart = @IsShoppingCart;";


 


              SqlParameter[] parms1 = {                   


                   new SqlParameter("@UniqueID", SqlDbType.Int),


                   new SqlParameter("@IsShoppingCart", SqlDbType.Bit)};


              parms1[0].Value = uniqueID;


              parms1[1].Value = isShoppingCart;


 


            if (cartItems.Count > 0) {


 


                // update cart using SqlTransaction


                string sqlInsert = "INSERT INTO Cart (UniqueID, ItemId, Name, Type, Price, CategoryId, ProductId, IsShoppingCart, Quantity) VALUES (@UniqueID, @ItemId, @Name, @Type, @Price, @CategoryId, @ProductId, @IsShoppingCart, @Quantity);";


 


                SqlParameter[] parms2 = {                 


                   new SqlParameter("@UniqueID", SqlDbType.Int), 


                   new SqlParameter("@IsShoppingCart", SqlDbType.Bit),


                   new SqlParameter("@ItemId", SqlDbType.VarChar, 10),


                   new SqlParameter("@Name", SqlDbType.VarChar, 80),


                   new SqlParameter("@Type", SqlDbType.VarChar, 80),


                   new SqlParameter("@Price", SqlDbType.Decimal, 8),


                   new SqlParameter("@CategoryId", SqlDbType.VarChar, 10),


                   new SqlParameter("@ProductId", SqlDbType.VarChar, 10),


                   new SqlParameter("@Quantity", SqlDbType.Int)};


                parms2[0].Value = uniqueID;


                parms2[1].Value = isShoppingCart;


 


                SqlConnection conn = new SqlConnection(SqlHelper.ConnectionStringProfile);


                conn.Open();


                SqlTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);


 


                try {


                    SqlHelper.ExecuteNonQuery(trans, CommandType.Text, sqlDelete, parms1);


 


                    foreach (CartItemInfo cartItem in cartItems) {


                        parms2[2].Value = cartItem.ItemId;


                        parms2[3].Value = cartItem.Name;


                        parms2[4].Value = cartItem.Type;


                        parms2[5].Value = cartItem.Price;


                        parms2[6].Value = cartItem.CategoryId;


                        parms2[7].Value = cartItem.ProductId;


                        parms2[8].Value = cartItem.Quantity;


                        SqlHelper.ExecuteNonQuery(trans, CommandType.Text, sqlInsert, parms2);


                    }


                    trans.Commit();


                }


                catch (Exception e) {


                    trans.Rollback();


                    throw new ApplicationException(e.Message);


                }


                finally {


                    conn.Close();


                }


            }


            else


                // delete cart


                SqlHelper.ExecuteNonQuery(SqlHelper.ConnectionStringProfile, CommandType.Text, sqlDelete, parms1);


         }


 


4.3 訂單處理技術 


 

訂單處理技術:――分佈式事務


 

1)  同步:直接在事務中 將訂單 插入到數據庫中,同時更新庫存


 

2)  異步:訂單-》消息隊列(使用MSMQ)-》後臺處理 


 

4.3.1 使用Wizard組件


 

4.3.2 分佈式事務處理技術


 

開啓MSDTC 服務支持分佈式事務. To start the MSDTC service, open Administrative Tools | Services and start the Distributed Transaction Coordinator service


 

4.3.3 MSMQ 消息隊列簡介


 


 

1)引用隊列


 

 


 

      引用隊列有三種方法,通過路徑、格式名和標籤引用隊列,這裏我只介紹最簡單和最常用的方法:通過路徑用隊列。隊列路徑的形式爲 machinename/queuename。指向隊列的路徑總是唯一的。下表列出用於每種類型的隊列的路徑信息:


 


 

如果是發送到本機上,還可以使用”.”代表本機名稱。


 

 


 

2)消息的創建


 

不過要使用MSMQ開發你的消息處理程序,必須在開發系統和使用程序的主機上安裝消息隊列。消息隊列的安裝屬於Windows組件的安裝,和一般的組件安裝方法類似。


 

往系統中添加隊列十分的簡單,打開[控制面板]中的[計算機管理],展開[服務和應用程序],找到並展開[消息隊列](如果找不到,說明你還沒有安裝消息隊列,安裝windows組件),右擊希望添加的消息隊列的類別,選擇新建隊列即可。


 

 


 

消息接收服務位於System.Messaging中,在初始化時引用消息隊列的代碼很簡單,如下所示:


 

MessageQueue Mq=new MessageQueue(.//private$//jiang)


 

 


 

通過Path屬性引用消息隊列的代碼也十分簡單:


 

MessageQueue Mq=new MessageQueue()


 

Mq.Path=”.//private$//jiang”;


 

 


 

使用Create 方法可以在計算機上創建隊列:


 

System.Messaging.MessageQueue.Create(@"./private$/jiang");


 

 


 

3) 發送和接收消息


 

過程:消息的創建-》發送-》接收-》閱讀-》關閉


 

簡單消息的發送示例如下:


 

         Mq.Send(1000); //發送整型數據


 

         Mq.Send(This is a test message!); //發送字符串


 

 


 

接收消息由兩種方式:通過Receive方法接收消息同時永久性地從隊列中刪除消息;通過Peek方法從隊列中取出消息而不從隊列中移除該消息。如果知道消息的標識符(ID),還可以通過ReceiveById方法和PeekById方法完成相應的操作。


 

     接收消息的代碼很簡單:


 

         Mq.Receive(); //Mq.ReceiveById(ID);


 

         Mq.Peek();  // Mq.PeekById(ID);


 

 


 

閱讀消息


 

接收到的消息只有能夠讀出來纔是有用的消息,因此接收到消息以後還必須能讀出消息,而讀出消息算是最複雜的一部操作了。消息的序列化可以通過Visual Studio .NET Framework 附帶的三個預定義的格式化程序來完成:XMLMessageFormatter 對象( MessageQueue 組件的默認格式化程序設置)、BinaryMessageFormatter 對象、ActiveXMessageFormatter 對象。由於後兩者格式化後的消息通常不能爲人閱讀,所以我們經常用到的是XMLMessageFormatter對象。


 

使用XMLMessageFormatter對象格式化消息的代碼如下所示:


 

       string[] types = { "System.String" };


 

       ((XmlMessageFormatter)mq.Formatter).TargetTypeNames = types;


 

        Message m=mq.Receive(new TimeSpan(0,0,3));


 

       將接收到的消息傳送給消息變量以後,通過消息變量mBody屬性就可以讀出消息了:


 

MessageBox.Show((string)m.Body);


 

 


 

關閉消息隊列


 

     消息隊列的關閉很簡單,和其他對象一樣,通過Close函數就可以實現了:


 

Mq.Close();


 

 


 

4.3.4 PetShop程序中訂單處理-使用同步消息


 

默認程序使用同步消息 處理,直接操作數據庫插入訂單,更新庫存類


 

4.3.5 PetShop程序中訂單處理-使用異步消息


 

1)    Web程序中調用PetShop.BLL.Order類方法:  Insert(OrderInfo order);


 

 


 

2)    PetShop.BLL.Order類


 

//IOrderStrategy接口中只有一個插入訂單方法:void Insert(PetShop.Model.OrderInfo order);


 

        //得到PetShop.BLL. OrderAsynchronous類


 

        private static readonly PetShop.IBLLStrategy.IOrderStrategy orderInsertStrategy = LoadInsertStrategy();


 

 


 

        //IOrder接口中有兩種方法:Send()與Receive()  -消息隊列


 

        private static readonly PetShop.IMessaging.IOrder orderQueue


 

= PetShop.MessagingFactory.QueueAccess.CreateOrder();


 

 


 

public void Insert(OrderInfo order) {


 

            // Call credit card procesor,採用隨機化方法設置訂單認證數字


 

            ProcessCreditCard(order);


 

            // Insert the order (a)synchrounously based on configuration


 

            orderInsertStrategy.Insert(order);    //調用PetShop.BLL.OrderAsynchronous


 

        }


 

 


 

3)    PetShop.BLL. OrderAsynchronous類


 

 


 

// CreateOrder()方法得到PetShop.MSMQMessaging .Order類的實例


 

private static readonly PetShop.IMessaging.IOrder asynchOrder


 

 = PetShop.MessagingFactory.QueueAccess.CreateOrder();


 

 


 

public void Insert(PetShop.Model.OrderInfo order) {


 

            asynchOrder.Send(order);    //調用PetShop.MSMQMessaging.Order類


 

        }


 

 


 

4)    PetShop.MSMQMessaging項目 -關鍵(發送/接收消息)


 

 


 

PetShopQueue基類:創建消息隊列,發送和接收消息


 

Order類:繼承自PetShopQueue類


 

public new OrderInfo Receive() {            //從隊列中接收消息


 

            base.transactionType = MessageQueueTransactionType.Automatic;


 

            return (OrderInfo)((Message)base.Receive()).Body;


 

        }


 

public void Send(OrderInfo orderMessage) {  //發送消息到隊列


 

            base.transactionType = MessageQueueTransactionType.Single;


 

            base.Send(orderMessage);


 

        }


 

 


 

5)    PetShop.OrderProcessor項目-後臺處理訂單,將它們插入到數據庫中


 

Program類:多線程後臺訂單處理程序,可寫成一個控制檯程序,作爲windows服務開啓


 轉至:http://bbs.zgkw.cn/showtopic-17213.aspx
發佈了43 篇原創文章 · 獲贊 3 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章