I almost forgot. These two articles are both reprinted and written by Zhu Xianzhong. Source: Tianji development. I am a little slow in network speed now. I won't change it in the previous article!
In this article, we will explore the GridView through a simple online store demo program and start to analyze a method to generate the DataSource of the GridView, then, use the data to create a fully functional shopping interface. Note that DataSource in this demo can be freely created.
I. Introduction
In the previous article, we discussed what a GridView is and how to use it, including how the actual data is bound to it. In this article, we will analyze the source of the data more closely and how to use it with the GridView to implement a simple Shopping interface.
2. Where does the data come from?
Basically, this problem depends on what you want to do. It can come from a static XML file, a dynamic XML feed, and a database. Maybe it is freely created. However, in any case, make sure that: if there is data, you can make sure that it can be "imported" into a GridView. In this article, this part of data is freely created every time you restart the application.
The DataSource used to fill two GridView is a DataTable. It is built using DataColumns and DataRows. There is a function called "createProductDT" in this main class file, which describes the initial creation method of the DataTable. The complete implementation of this function is as follows:
Private DataTable createProductDT () { DataTable dtProducts = new DataTable (); DataColumn productColumn = new DataColumn (); ProductColumn. DataType = System. Type. GetType ("System. Int32 "); ProductColumn. ColumnName = "id "; ProductColumn. Unique = true; DtProducts. Columns. Add (productColumn ); ProductColumn = new DataColumn (); ProductColumn. DataType = System. Type. GetType ("System. String "); ProductColumn. ColumnName = "thumb "; DtProducts. Columns. Add (productColumn ); ProductColumn = new DataColumn (); ProductColumn. DataType = System. Type. GetType ("System. String "); ProductColumn. ColumnName = "name "; DtProducts. Columns. Add (productColumn ); ProductColumn = new DataColumn (); ProductColumn. DataType = System. Type. GetType ("System. Double "); ProductColumn. ColumnName = "price "; DtProducts. Columns. Add (productColumn ); ProductColumn = new DataColumn (); ProductColumn. DataType = System. Type. GetType ("System. Int32 "); ProductColumn. ColumnName = "quantity "; DtProducts. Columns. Add (productColumn );// Make "id" a primary key DataColumn [] pkColumns = new DataColumn [1]; PkColumns [0] = dtProducts. Columns ["id"]; DtProducts. PrimaryKey = pkColumns; Return dtProducts; } |
First, we create a able object and then create a DataColumn. For most table columns, we only need to set the data type and column name, although for the first column ("id"), we also need to set it as unique. This is because we want to use it as our primary key. In addition, we need to configure it at the end of the function. The reason we want to make the id always unique is that we need to use it to reference various products we will add to DataSource later. In this way, we can select specific data from it, for example, only the product price and product name are used. This function returns an empty able and is therefore only used in getBasket () and populateProducts.
Now, we will add the actual row data to the DataSource in populateProducts (). For details, see the following code. Each line corresponds to a different product. Adding a new row to a DataTable requires you to create a new DataRow and then call the NewRow () function of the DataTable. This will leave a position for the new row in the DataTable, but it will not actually add the row.
Private void populateProducts () { // Create the basic structure DataTable dtProducts = createProductDT (); // Add the product to it // Create the initial row DataRow aProduct = dtProducts. NewRow (); AProduct ["id"] = 11; AProduct ["thumb"] = "images/widget0.jpg "; AProduct ["name"] = "Red Widget "; AProduct [& quot; price & quot;] = 19.99; DtProducts. Rows. Add (aProduct ); // Reuse this row to add a new product AProduct = dtProducts. NewRow (); AProduct ["id"] = 22; AProduct ["thumb"] = "images/widget1.jpg "; AProduct ["name"] = "Green Widget "; AProduct [& quot; price & quot;] = 50.99; DtProducts. Rows. Add (aProduct ); // Bind the DataTable to the product GridView GvProducts. DataSource = dtProducts; GvProducts. DataBind ();// Store the product to Session Session ["dtProducts"] = dtProducts; } |
First, we need to add some data to the row (such as the id, path, name, and price of the thumbnail image ). Once the content is added, we can call the Add () function to actually Add our new row to the DataTable. In this demo, we added six products, although we added only two in the above snippet. You can see how I implement "spoofing" and only reuse the same columns and rows. Once this is done, we bind the able to our GridView. For details, see the following code:
GvProducts. DataSource = dtProducts; GvProducts. DataBind (); |
Do you still remember the RowDataBound event we discussed in the first article? Well, once we call DataBind (), this function is activated to create data on the page. You should be aware that there may be other events between the two events at the underlying implementation level. However, to make it easier to understand, we only consider these two events.
Since then, we have stored a copy of The DataTable in the session State. In this way, we can retrieve it directly every time we want to access the product data, without having to recreate it. It is worth noting that, although this situation is more suitable for a small part of the data for a small project; but for large applications, you should not use the session state like in this example-it will easily "Swallow" your server memory; therefore, even if you use part of the data, it may also use a large amount of memory, if there are thousands of users accessing it at the same time. In this demo, you will see that the data is extracted multiple times from the session; however, in practice, you may implement multiple database calls to extract specific data subsets (when needed ).
One thing worth noting is that you can set "DataKeyNames", which can be used to index items in the GridView. The product list and shopping basket both implement a single DataKeyName:
In this way, you can use it when you click "Add to basket" to identify the product you want to Add. In the basket, use it when updating the quantity. You can have multiple key names, although in most cases you only need one.
Before filling in the GridView, You can bind an empty able to it. This will force it to display a blank line (you can use a string to pre-fill ). In this demonstration, this is implemented using two GridView, although you can only see one of them corresponds to the shopping basket, because even if there is no product in your store, it is not important. You can use the "EmptyDataText" GridView attribute to set it as follows:
EmptyDataText = "~ Basket is empty ~ " |
Then, it will be generated like 1:
Figure 1. Prompt when the basket is empty. |
3. Shopping Basket
Figure 2. Shopping Basket implemented in the sample program. |
The shopping basket (see figure 2) is used to store products (customers can select from the product list by clicking "Add to basket" next to each product ). It is good to store the shopping basket in the session state, because in a complete shopping, when the customer decides to leave your site at any time, or may leave their shopping basket empty, all such data may be discarded. Of course, for a number of reasons, for example, you can choose to store the contents of the customer's shopping basket in a database to identify who is analyzing and judging the shopping trend for the purpose of market research. Another reason may be to show them the "Last time you were here you looked at these items..." type display. This requires that you have a way to differentiate customers. Two common technologies are used to store a cookie in a user's system-identify their future access by using a unique ID, or use their Login ID to Make a Difference (if you have achieved Customer Login ).
The updated shopping basket also uses the createProductDT () function to create its initial empty DataTable. In this demo, we will use the same table structure, but you can delete some data columns to further "refine" your shopping basket. In most cases, you only need to store the ID and quantity of each product, because you can easily find the actual product details based on its ID.
Each time a product is added to the basket through the product list, its "Add to basket" button activates an OnServerClick event:
Protected void shopBuy_OnServerClick (object source, EventArgs e) { Int index = (GridViewRow) (HtmlInputButton) source). Parent. NamingContainer). RowIndex; AddToBasket (Convert. ToInt32 (gvProducts. DataKeys [index]. Value )); } Protected void addToBasket (int productID) { DataTable dtBasket = getBasketDt (); // Traverse the shopping basket cyclically and check whether this item already exists Bool found = false; For (int I = 0; I <dtBasket. Rows. Count; I ++) { If (Convert. ToInt32 (dtBasket. Rows [I] ["id"]) = productID) { // Increase the number and mark it as discovered DtBasket. Rows [I] ["quantity"] = Convert. ToInt32 (dtBasket. Rows [I] ["quantity"]) + 1; Found = true; // Jump out of the loop when we have found one Break; } } // If this item cannot be found, add it as a new row If (! Found) { DataTable dtProducts = getProductsDt (); DataRow drProduct = dtProducts. Rows. Find (productID ); // Now that we have obtained the required data from the data source, we will add a new row to the shopping basket. DataRow newRow = dtBasket. NewRow (); NewRow ["id"] = drProduct ["id"]; NewRow ["name"] = drProduct ["name"]; NewRow ["price"] = drProduct ["price"]; NewRow ["quantity"] = 1; DtBasket. Rows. Add (newRow ); } // Store the newly updated shopping basket back to the session Session ["dtBasket"] = dtBasket; // Update the shopping basket, that is, "rebind it" UpdateShopBasket (); } |
We use the shopBuy_OnServerClick () function to "capture" this point (this function can identify the row of the button), get the ID of the relevant product, and use it to call addToBasket (). In this function, we can use the given product ID to check the shopping basket. If it already exists in the shopping basket, we need to increase its quantity. If it does not exist, we will add it as a new row. Finally, we rebind the shopping basket to its updated DataSource. See figure 3.
The shopping basket also uses TemplateColumns, just like the product GridView. Therefore, we can create a quantity text box on each row. This provides customers with an easy way to update the number of each item they require. Once they change these values, they click the "Update Quantities" button under the basket. This will activate an OnServerClick event captured by shopUpdateBasketQuantities_OnServerClick. This is similar to the addToBasket () function: We must locate the product in the shopping basket and then update its quantity. The difference is that when we check the data retrieved from the text box, we must be careful, because you have no idea who can enter it to mess up your system. The following code snippet of the function that handles this check:
// Read data from the Quantity text box HtmlInputText itQuant = (HtmlInputText) row. FindControl ("itProductQuantity "); // Convert the value into an integer Try { Int quant = Convert. ToInt32 (itQuant. Value );/* If the value is successfully converted into an integer Check that it is not a negative number; otherwise, we may owe Customer money! */ If (quant> 0) { DrProduct ["quantity"] = quant; } Else { DrProduct. Delete (); } } Catch { // If we cannot convert it to an integer, We will not change it. } |
For example, if someone enters-100 in the quantity field, you may still owe them money! However, in general, you may not pay for them, but it depends on how your payment system is built. For this reason, we wrap the integer analysis into a try/catch Block so that we can keep the original value unchanged without analysis. Afterwards, we will check this quantity to make sure it is greater than zero. If it is less than or equal to zero, we will delete this row. Finally, after checking all the products in the shopping basket and modifying their respective quantities, we will save the shopping basket and update the display.
The last key component of the shopping basket is the updateShopBasket () function:
Private void updateShopBasket () { GvBasket. DataSource = getBasketDt (); GvBasket. DataBind (); IbEmptyBasket. Visible = ibUpdateBasketQuantities. Visible = ibBasketCheckout. Visible = gvBasket. Rows. Count> 0; } |
This function can extract a copy of the basket from the session state, which in turn creates a session basket, if it does not exist, and then binds it to the GridView. The ultimate goal is to hide or display three shopping basket buttons, because they are not needed if the shopping basket is empty.
4. A noteworthy security question
Users in your system should strictly control wherever they have the opportunity to input data to ensure that they do not enter anything they do not want to implement. A common problem is SQL injection. In this position, some people can enter the SQL code into a part of a site, and then you can use it in the original SQL statement you want to use. For example, you can use:
"UPDATE tbl_basket SET quantity =" + quantity. Text + "WHERE user_id =" + user_id; |
If the customer enters 6 in the "quantity" text box and their logon id is 230, the above Code will look like:
UPDATE tbl_basket SET quantity = 6 WHERE user_id = 230; |
If the customer inputs:
"1 WHERE 1 = 1; DROP tbl_users ;--" |
The original statement now looks like:
UPDATE tbl_basket SET quantity = 1 WHERE 1 = 1; DROP tbl_users; -- WHERE user_id =; |
In this way, they can use "1 WHERE 1 = 1;" to complete the original statement, and then continue the "Drop tbl _ users;" operation, which is bad! Finally, they can comment out other parts of the original statement. In fact, this is only an extremely simple example. You can find a lot of information about SQL Injection on your website.
5. Payment
There are many ways to receive payments using e-business methods. There are several types listed below:
· An online store is not just an online directory. Customers often have to contact you by phone for ordering.
· Similar to the above situation, unless you find the customer in person to complete the entire transaction. This may be important if it is about some architectural work (such as a yard or a kitchen) and you need to make a quotation to them on the spot after field trips.
· Use a built-in and secure payment method. In this way, customers can enter their credit card details and the system can automatically process transactions.
· Use an external payment method, such as PayPal, Worldpay, or DebiTech.
The demo store in this article is based on an old-style Method of Using PayPal to receive payments. It should work with other external payment systems (such as slightly modified WorldPay. The reason we say "Old Style" is that today's PayPal generally provides its own. net toolkit-to implement their own systems connected to their sites.
The whole system that collects basket data and transfers it to PayPal is implemented in the shopBasketCheckout_OnServerClick () function:
Protected void shopBasketCheckout_OnServerClick (object source, EventArgs e) { String postData = ""; PostData + = "currency_code = GBP "; PostData + = "& cmd = _ cart "; PostData + = "& business = youremailaddress@yourdomain.net "; PostData + = "& upload = 1 "; PostData + = "& cancel_return = www.david millington.net "; DataTable dtBasket = getBasketDt (); Double total = 0.00; For (int I = 0; I <dtBasket. Rows. Count; I ++) { PostData + = "& item_name _" + (I + 1) + "=" + DtBasket. Rows [I] ["name"]; PostData + = "& quantity _" + (I + 1) + "=" + DtBasket. Rows [I] ["quantity"]; PostData + = "& amount _" + (I + 1) + "=" + Convert. ToDouble (dtBasket. Rows [I] ["price"]); Total + = (Convert. ToDouble (dtBasket. Rows [I] ["Price"]) * Convert. ToInt32 (dtBasket. Rows [I] ["quantity"]); If (I = dtBasket. Rows. Count-1) { PostData + = "& shipping _" + (I + 1) + "=" + calcDeliveryCost (total ); } Else { PostData + = "& shipping _" + (I + 1) + "= 0.00 "; } PostData + = "& shipping2 _" + (I + 1) + "= 0.00 "; PostData + = "& handling _" + (I + 1) + "= 0.00 "; } PostData + = "& handling =" + calcDeliveryCost (total ); Byte [] data = Encoding. ASCII. GetBytes (postData ); HttpWebRequest ppRequest = (HttpWebRequest) WebRequest. Create ("https://www.paypal.com/cgi-bin/webscr ");; PpRequest. Method = "POST "; PpRequest. ContentType = "application/x-www-form- Urlencoded "; PpRequest. ContentLength = data. Length; // Send Stream ppStream = ppRequest. GetRequestStream (); PpStream. Write (data, 0, data. Length ); PpStream. Close (); // Receive HttpWebResponse ppResponse = (HttpWebResponse) ppRequest. GetResponse (); StreamReader sr = new StreamReader (ppResponse. GetResponseStream ()); String strResult = sr. ReadToEnd (); Sr. Close (); // Output to the screen Response. Clear (); Response. Write (strResult ); Response. End (); } |
Because there seems to be no way to send a C # application and redirect it to another site (as you usually implement with a <form> action attribute ), therefore, we must adopt a slightly different method. We have constructed a long string that contains multiple name/value pairs, and then uses the HttpWebRequest and HttpWebResponse objects to send and receive data back and forth from the payment service.
The first part of the function specifies the PayPal account details, such as the currency used, the account name, and the page that PayPal should return to the customer (if they decide to cancel the transaction ).
The next step is to traverse the shopping basket and retrieve all the product information we want to pass to PayPal. This includes the product name, quantity, and price. Due to the characteristics of this demo, we applied a little skill in shipping costs and added the entire shipping cost to the last product in the basket instead of to each product. This is because we only calculate the total transportation cost based on the total price of the shopping basket, rather than based on any product type.
Now let's discuss the interesting part. I admit that this is the result of my Google engine query. First, create a Request object and use it when we contact PayPal through a Stream. We use a Response object to receive the Response and simply output it to the screen through Response. Write. This can transfer the entire shopping basket information to the PayPal site and direct it to the correct account.
The problem is that the first page that the customer arrived still has your store address in the corresponding address bar. If they click any link to the PayPal site, such as viewing the content of the shopping basket or logging on to it, the address should be changed accordingly to reflect that it is actually a PayPal site. You may realize that some people may be misunderstood, because of this fact-they can still see the address of your store in the address bar and may even think that you are trying to defraud them of PayPal or bank account details. If you are planning to make a payment via an external system such as PayPal or WorldPay, you should check their developer site to see what their. net solution is.
Vi. Conclusion
In this section, we first analyze a method for generating the DataSource of the GridView, and then continue to use this data to create a full-featured shopping interface. Although DataSource in this demo can be created freely, if you have a large number of products or only one product line that is frequently changed, you must consider using a database to store your product information. Of course, adding a database to the system is more like opening its own virus database. Therefore, this is an option that should not be taken easily.
Pay special attention to the payment system. The demo store uses a simple method to collect requested basket information and send it to an external payment system. You may want to use more controls for payment processing, such as extracting the customer's payment details and storing them in a database, or writing your own electronic sales point functions. Whatever method you choose, you should be aware of the legitimacy of receipt and payment in your country.
In the next article of this series, we will discuss how to change the appearance of the GridView.