浅析PetShop程序中的购物车和订单处理模块(Profile技术,异步MSMQ消息)

对于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服务开启

处理队列中的批量异步订单,在事务范围内把它们提交到数据库

转载于:https://www.cnblogs.com/hnsjack/articles/608501.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html5设置视频显示第一帧,如何检测HTML5视频何时播放第一帧?

还有另一种方法可以使用currentTime并为视频更改的每个时间定义一个函数。在HTML5视频元素顶部设置div&#xff0c;并在currentTime在3到4秒之间时修改该元素。示例代码应该是这样的&#xff1a;HTML&#xff1a;Your browser does not support HTML5 video.CSS&#xff1a;#vi…

maven 公共模块依赖_「spring-boot 源码解析」spring-boot 依赖管理

问题maven 工程&#xff0c;依赖管理是非常基本又非常重要的功能&#xff0c;现在的工程越来越庞大&#xff0c;依赖越来越多&#xff0c;各种二方包、三方包太多太多&#xff0c;依赖冲突处理起来真是让人头疼&#xff0c;经常需要涉及到多个地方需要调整。微信公众号&#xf…

【转】ABP源码分析三十五:ABP中动态WebAPI原理解析

动态WebAPI应该算是ABP中最Magic的功能之一了吧。开发人员无须定义继承自ApiController的类&#xff0c;只须重用Application Service中的类就可以对外提供WebAPI的功能&#xff0c;这应该算是对DRY的最佳诠释了. 如下图所示&#xff0c;一行代码就为所有实现了IApplicationSer…

计算机科学与探索 影响因子,《计算机科学与探索》国家级计算机期刊投稿论文发表...

《计算机科学与探索》国家级计算机期刊投稿论文发表《计算机科学与探索》杂志简介-是不是正规期刊&#xff1a;《计算机科学与探索》是由中华人民共和国工业和信息化部主管、华北计算技术研究所361期刊网主办的国内外公开发行的计算机学报级高级学术期刊&#xff0c;中国计算机…

如何将SAP数据传输到其他系统(Transferring Data from SAP to Other Systems)

在sap里有GUI_DOWNLOAD 函数将sap的数据下载到客户端机器&#xff08;presentation server&#xff09;&#xff0c;而Dataset则是将数据传输到应用服务器&#xff08;Application server&#xff09;。然而在有些时候需要将数据传输到第三方其他系统(3rd Party System)&#x…

jstl处理栏目与子栏目_Detelogy智能前处理设备微展厅P2:再添新品

时隔小半年&#xff0c;新一轮Detelogy产品总览展示栏目再与大家见面。事不宜迟&#xff0c;点击视频即刻进入我们的智能前处理设备微展厅。 知乎视频​www.zhihu.com01 高效多样品前处理系统02 智能浓缩设备全系列03 智能湿法消解设备应用领域农残、兽残检测有机磷类、有机氯类…

【转】ABP源码分析三十六:ABP.Web.Api

这里的内容和ABP 动态webapi没有关系。除了动态webapi&#xff0c;ABP必然是支持使用传统的webApi。ABP.Web.Api模块中实现了一些同意的基础功能&#xff0c;以方便我们创建和使用asp.net webApi。 AbpApiController&#xff1a;这是一个抽象基类&#xff0c;继承自ApiControl…

408最后计算机网络题库,2021考研计算机统考408专业基础综合题库

**部分为历年考研真题。提供2009&#xff5e;2018年考研真题及参考答案&#xff0c;其中2009&#xff5e;2015年每道真题均提供详细答案解析&#xff0c;通过对真题的演练和分析&#xff0c;可以帮助学员牢牢抓住计算机学科专业基础综合考试的命题特点&#xff0c;提高复习效率…

Unity-Shader-渲染队列,ZTest,ZWrite

Unity-Shader-渲染队列&#xff0c;ZTest&#xff0c;ZWrite ZTest&#xff08;深度测试&#xff09;和ZWrite&#xff08;深度写入&#xff09;ZTest Less&#xff08;深度小于当前缓存则通过&#xff09;ZTest Greater&#xff08;深度大于当前缓存则通过&#xff09;ZTest L…

如何做好职业规划(乾卦)

职业一般来说会占用我们每个人生命中的大部分时间&#xff0c;而职业发展中变化莫测的因数常常令我们束手无策、捉襟见肘。在面对变化多端的情况时&#xff0c;中国人的传统智慧就发挥出最大的优势了。如何将快速变化 、不好掌控的事情处理得井井有条&#xff0c;这需要我们懂得…

850是什么意思_沃尔沃为什么不是一线豪华品牌?

1927年诞生的沃尔沃&#xff0c;它造车的历史比宝马还要略早几年。但经过近百年的发展&#xff0c;宝马品牌无论在国际上还是我们国内&#xff0c;以销量还是品牌含金量来看&#xff0c;都是众所公认的豪华品牌第一阵营成员&#xff08;奔驰、宝马&#xff0c;奥迪&#xff09;…

【转】ABP源码分析三十七:ABP.Web.Api Script Proxy API

ABP提供Script Proxy WebApi为所有的Dynamic WebApi生成访问这些WebApi的JQuery代理&#xff0c;AngularJs代理以及TypeScriptor代理。这些个代理就是javascript脚本,通过这些代理可以简单的访问Dynamic webApi。 如下实例演示一个最基本的应用场景。首先通过Script Proxy Web…

repeater导出excel html,Repeater显示数据,并且导出到excel

我的数据是自己手工生产&#xff0c;然后repeater绑定&#xff0c;最后导出excel&#xff0c;但出现问题&#xff0c;谁可以给个例子什么的没有。关键代码如下&#xff1a;protected void LinkButton1_Click(object sender, EventArgs e){string time DateTime.Now.ToString(&…

重新学.Net[一]——.Net的组成

.Net是一个广义的名词。它是一个平台或说是战略。在.Net诞生之初&#xff0c;微软在其一系列产品中都冠以.Net的标签。这也给很多人带来疑惑和不解&#xff0c;到底.Net中具体包含什么&#xff1f;这个问题不仅是我有&#xff0c;我想&#xff0c;甚至微软本身以及一些专家也会…

word2003如何设置护眼模式_手机屏幕的护眼模式是如何保护你的眼睛?

公司业务包括&#xff1a;二手机回收&#xff0c;二手机销售&#xff0c;配件批发&#xff0c;以及手机维修等业务&#xff0c;目前公司业务覆盖山西全境以及周边省市&#xff0c;在同行业有较高知名度。 随着智能手机的普及&#xff0c;大多数人也逐渐开始沉迷于每天的刷手…

WinCE系统的编译过程

作者&#xff1a;ARM-WinCE 在WinCE系统中&#xff0c;当我们完成了相关的开发和系统定制工作以后&#xff0c;会编译WinCE系统&#xff0c;最后生成NK.bin和NK.nb0。我现在用WinCE6.0在自己的PC上面编译一次用时19分16秒(有一天无聊&#xff0c;就测了一下)。下面介绍一下WinC…

【转】ABP源码分析三十八: ABP.Web.Api.OData

如果对OData不熟悉的话可参考OData的初步认识一文以获取OData的一些初步知识。 API.Odata 模块唯一用处就是提供了一个泛型版本的ODataController&#xff0c;实现了Controller代码的常用。 AbpODataEntityController<TEntity, TPrimaryKey>&#xff1a;使用ABP的repos…

由表单中onsubmit=return false;想到的

众所周知&#xff0c;在表单中加上οnsubmit"return false;"可以阻止表单提交。 下面是简单的一小段代码&#xff1a; 代码<form action"index.jsp" method"post" onsubmit"submitTest();"> <INPUT value"www">…

计算机知识竞赛主持人开场词,护理竞赛主持人台词:主持人开场白台词

专科护理在世界范围内蓬勃发展&#xff0c;高质量的专科护理人才是推动护理事业发展的原动力。下面是小编给大家整理的护理竞赛主持人台词&#xff0c;仅供参考。护理竞赛主持人台词【篇一】在这充满火热激情的季节&#xff0c;我们又迎来了“5.12国际护士节”。让我们首先向辛…

饭卡可以用水冲洗吗_薄壁不锈钢水管真的可以满足大众用水健康管道的要求吗?...

我们都认识现如今的自来水的出厂干净程度达到安全、卫生&#xff0c;干净标准。但是&#xff0c;很是收到不少市民的投诉&#xff0c;说日常饮用的自来水有异味、浑浊、杂质&#xff0c;为何会出现这番现象呢&#xff0c;为此&#xff0c;我国也针对此研究调查&#xff0c;最后…