Desarrollar un carrito de compras en ASP.NET
Spanish (Español) translation by Steven (you can also view the original English article)
Los carritos de compras son muy importantes y muchas veces pueden ser la parte más intimidante del desarrollo de un sitio de comercio electrónico. Este tutorial te mostrará qué tan fácil puede ser implementar un carrito de compras utilizando ASP.NET. Además, se proporcionarán varias explicaciones básicas para ayudar a los programadores principiantes de ASP.NET a comprender este maravilloso framework.


Descripción rápida de ASP.NET

Dado que ASP.NET no se ha cubierto demasiado en NETTUTS, pensé que sería bueno incluir una breve descripción de algunas de las cosas que lo distinguen de otros idiomas.
- El código está compilado. La primera vez que se solicita una página ASP.NET a través de la web, el código se compila en uno o más archivos DLL en el servidor. Esto te brinda la capacidad de simplemente copiar el código al servidor y te brinda el beneficio de la velocidad del código compilado.
- ASP.NET es un framework orientado a objetos. Cada función, propiedad y página es parte de una clase. Por ejemplo, cada página web es su propia clase que extiende la clase Page. La clase Page tiene un evento que se activa cuando se carga la página web llamada "Evento de carga de página". Puedes escribir una función que se suscriba a ese evento y se active. El mismo principio se aplica a otros eventos como el clic del botón y los eventos "desplegables" del "índice seleccionado".
- La lógica está separada del diseño y del contenido. Ellos interactúan entre sí, pero están en lugares separados. Generalmente, esto permite que un diseñador haga lo suyo sin preocuparse por la función y le permite al programador enfocarse en la función sin mirar el diseño. Tiene la opción de ponerlos en el mismo archivo o en archivos diferentes. Esto es similar al modelo MVC (Modelo Vista y Controlador)


Si eres nuevo en ASP.NET (y tienes Windows), puedes probarlo gratis. Puedes descargar Visual Studio Express visitando el sitio web de ASP.NET. Además, cuando creas un sitio web localmente en tu máquina, puedes ejecutar el sitio web en cualquier momento y Visual Studio iniciará rápidamente un servidor en tu computadora y lo abrirá en tu navegador predeterminado.
Paso 1: Crea la clase ShoppingCart
Necesitamos un lugar para almacenar los artículos en el carrito de compras, así como funciones para manipularlos. Vamos a crear una clase ShoppingCart para esto. Esta clase también gestionará el almacenamiento de sesión.
Primero, tenemos que crear la carpeta App_Code. Para hacer esto, ve al menú "Sitio web", luego "Agregar carpeta ASP.NET", y elige "Código de aplicación". Aquí es donde pondremos todas nuestras clases personalizadas. Se podrá acceder a estas clases automáticamente desde el código en cualquiera de nuestras páginas (no es necesario que hagamos referencia usando algo similar a "include" ni nada). Luego podemos agregar una clase a esa carpeta haciendo clic derecho en la carpeta y seleccionando "Agregar nuevo elemento".
Sugerencia rápida: Las regiones en ASP.NET son realmente agradables de organizar y agrupar código. Lo mejor de ellos es que puedes abrir y cerrar regiones para minimizar la cantidad de código que estás buscando o buscar rápidamente un camino alrededor de un archivo.

1 |
|
2 |
using System.Collections.Generic; |
3 |
using System.Web; |
4 |
|
5 |
/**
|
6 |
* The ShoppingCart class
|
7 |
*
|
8 |
* Holds the items that are in the cart and provides methods for their manipulation
|
9 |
*/
|
10 |
public class ShoppingCart { |
11 |
#region Properties |
12 |
|
13 |
public List<CartItem> Items { get; private set; } |
14 |
|
15 |
#endregion |
16 |
|
17 |
#region Singleton Implementation |
18 |
|
19 |
|
20 |
|
21 |
// Readonly properties can only be set in initialization or in a constructor
|
22 |
public static readonly ShoppingCart Instance; |
23 |
|
24 |
// The static constructor is called as soon as the class is loaded into memory
|
25 |
static ShoppingCart() { |
26 |
// If the cart is not in the session, create one and put it there
|
27 |
// Otherwise, get it from the session
|
28 |
if (HttpContext.Current.Session["ASPNETShoppingCart"] == null) { |
29 |
Instance = new ShoppingCart(); |
30 |
Instance.Items = new List<CartItem>(); |
31 |
HttpContext.Current.Session["ASPNETShoppingCart"] = Instance; |
32 |
} else { |
33 |
Instance = (ShoppingCart)HttpContext.Current.Session["ASPNETShoppingCart"]; |
34 |
}
|
35 |
}
|
36 |
|
37 |
// A protected constructor ensures that an object can't be created from outside
|
38 |
protected ShoppingCart() { } |
39 |
|
40 |
#endregion |
41 |
|
42 |
#region Item Modification Methods |
43 |
/**
|
44 |
* AddItem() - Adds an item to the shopping
|
45 |
*/
|
46 |
public void AddItem(int productId) { |
47 |
// Create a new item to add to the cart
|
48 |
CartItem newItem = new CartItem(productId); |
49 |
|
50 |
// If this item already exists in our list of items, increase the quantity
|
51 |
// Otherwise, add the new item to the list
|
52 |
if (Items.Contains(newItem)) { |
53 |
foreach (CartItem item in Items) { |
54 |
if (item.Equals(newItem)) { |
55 |
item.Quantity++; |
56 |
return; |
57 |
}
|
58 |
}
|
59 |
} else { |
60 |
newItem.Quantity = 1; |
61 |
Items.Add(newItem); |
62 |
}
|
63 |
}
|
64 |
|
65 |
/**
|
66 |
* SetItemQuantity() - Changes the quantity of an item in the cart
|
67 |
*/
|
68 |
public void SetItemQuantity(int productId, int quantity) { |
69 |
// If we are setting the quantity to 0, remove the item entirely
|
70 |
if (quantity == 0) { |
71 |
RemoveItem(productId); |
72 |
return; |
73 |
}
|
74 |
|
75 |
// Find the item and update the quantity
|
76 |
CartItem updatedItem = new CartItem(productId); |
77 |
|
78 |
foreach (CartItem item in Items) { |
79 |
if (item.Equals(updatedItem)) { |
80 |
item.Quantity = quantity; |
81 |
return; |
82 |
}
|
83 |
}
|
84 |
}
|
85 |
|
86 |
/**
|
87 |
* RemoveItem() - Removes an item from the shopping cart
|
88 |
*/
|
89 |
public void RemoveItem(int productId) { |
90 |
CartItem removedItem = new CartItem(productId); |
91 |
Items.Remove(removedItem); |
92 |
}
|
93 |
#endregion |
94 |
|
95 |
#region Reporting Methods |
96 |
/**
|
97 |
* GetSubTotal() - returns the total price of all of the items
|
98 |
* before tax, shipping, etc.
|
99 |
*/
|
100 |
public decimal GetSubTotal() { |
101 |
decimal subTotal = 0; |
102 |
foreach (CartItem item in Items) |
103 |
subTotal += item.TotalPrice; |
104 |
|
105 |
return subTotal; |
106 |
}
|
107 |
#endregion |
108 |
}
|
Paso 2: El Cartitem y las clases de productos
Con un lugar para almacenar los artículos de nuestro carrito de compras, necesitamos poder almacenar información sobre cada artículo. Crearemos una clase de CartItem que hará esto. También crearemos una clase simple llamada Product que simulará una forma de obtener datos de los productos que estamos vendiendo.
La clase Cartitem:
1 |
|
2 |
using System; |
3 |
|
4 |
/**
|
5 |
* The CartItem Class
|
6 |
*
|
7 |
* Basically a structure for holding item data
|
8 |
*/
|
9 |
public class CartItem : IEquatable<CartItem> { |
10 |
#region Properties |
11 |
|
12 |
// A place to store the quantity in the cart
|
13 |
// This property has an implicit getter and setter.
|
14 |
public int Quantity { get; set; } |
15 |
|
16 |
private int _productId; |
17 |
public int ProductId { |
18 |
get { return _productId; } |
19 |
set { |
20 |
// To ensure that the Prod object will be re-created
|
21 |
_product = null; |
22 |
_productId = value; |
23 |
}
|
24 |
}
|
25 |
|
26 |
private Product _product = null; |
27 |
public Product Prod { |
28 |
get { |
29 |
// Lazy initialization - the object won't be created until it is needed
|
30 |
if (_product == null) { |
31 |
_product = new Product(ProductId); |
32 |
}
|
33 |
return _product; |
34 |
}
|
35 |
}
|
36 |
|
37 |
public string Description { |
38 |
get { return Prod.Description; } |
39 |
}
|
40 |
|
41 |
public decimal UnitPrice { |
42 |
get { return Prod.Price; } |
43 |
}
|
44 |
|
45 |
public decimal TotalPrice { |
46 |
get { return UnitPrice * Quantity; } |
47 |
}
|
48 |
|
49 |
#endregion |
50 |
|
51 |
// CartItem constructor just needs a productId
|
52 |
public CartItem(int productId) { |
53 |
this.ProductId = productId; |
54 |
}
|
55 |
|
56 |
/**
|
57 |
* Equals() - Needed to implement the IEquatable interface
|
58 |
* Tests whether or not this item is equal to the parameter
|
59 |
* This method is called by the Contains() method in the List class
|
60 |
* We used this Contains() method in the ShoppingCart AddItem() method
|
61 |
*/
|
62 |
public bool Equals(CartItem item) { |
63 |
return item.ProductId == this.ProductId; |
64 |
}
|
65 |
}
|
La clase Product:
1 |
|
2 |
/**
|
3 |
* The Product class
|
4 |
*
|
5 |
* This is just to simulate some way of accessing data about our products
|
6 |
*/
|
7 |
public class Product |
8 |
{
|
9 |
|
10 |
public int Id { get; set; } |
11 |
public decimal Price { get; set; } |
12 |
public string Description { get; set; } |
13 |
|
14 |
public Product(int id) |
15 |
{
|
16 |
this.Id = id; |
17 |
switch (id) { |
18 |
case 1: |
19 |
this.Price = 19.95m; |
20 |
this.Description = "Shoes"; |
21 |
break; |
22 |
case 2: |
23 |
this.Price = 9.95m; |
24 |
this.Description = "Shirt"; |
25 |
break; |
26 |
case 3: |
27 |
this.Price = 14.95m; |
28 |
this.Description = "Pants"; |
29 |
break; |
30 |
}
|
31 |
}
|
32 |
|
33 |
}
|
Definición: Una "propiedad" (property) en ASP.NET es una variable en una clase que tiene un setter, un getter, o ambos. Esto es similar a otros idiomas, pero en ASP.NET, la palabra "property" se refiere específicamente a esto. Un ejemplo de esto es la propiedad ProductId en la clase CartItem. No es simplemente una variable en una clase con un método para obtenerla o establecerla. Se declara de una manera especial con los bloques get {} y set {}.
Vamos a añadir artículos al carrito
Después de tener nuestras cabezas en el código durante tanto tiempo, es hora de que hagamos algo visual. Esta página simplemente será una forma de agregar artículos al carrito. Todo lo que necesitamos es algunos artículos con enlaces "Agregar al carrito". Pongamos este código en la página Default.aspx.
1 |
|
2 |
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> |
3 |
|
4 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5 |
|
6 |
<html xmlns="http://www.w3.org/1999/xhtml"> |
7 |
<head runat="server"> |
8 |
<title>My Store</title> |
9 |
<link href="Styles/StyleSheet.css" rel="stylesheet" type="text/css" /> |
10 |
</head>
|
11 |
<body>
|
12 |
|
13 |
<form id="form1" runat="server"> |
14 |
|
15 |
<div class="container"> |
16 |
<h1>My Store</h1> |
17 |
|
18 |
<div class="products"> |
19 |
<div>Shoes - <asp:LinkButton runat="server" ID="btnAddShirt" OnClick="btnAddShoes_Click">Add To Cart</asp:LinkButton></div> |
20 |
|
21 |
<div>Shirt - <asp:LinkButton runat="server" ID="btnAddShorts" OnClick="btnAddShirt_Click">Add To Cart</asp:LinkButton></div> |
22 |
<div>Pants - <asp:LinkButton runat="server" ID="btnAddShoes" OnClick="btnAddPants_Click">Add To Cart</asp:LinkButton></div> |
23 |
</div>
|
24 |
|
25 |
|
26 |
<a href="ViewCart.aspx">View Cart</a> |
27 |
</div>
|
28 |
|
29 |
</form>
|
30 |
</body>
|
31 |
</html>
|
Como puedes ver, lo único que sucede aquí es que tenemos algunos LinkButtons que tienen asociados los controladores de eventos OnClick.
En la página de código subyacente, tenemos 4 manejadores de eventos. Tenemos uno para cada LinkButton que solo agrega un artículo al carrito de compras y redirige al usuario para que vea su carrito. También tenemos un controlador de eventos Page_Load que es creado por el IDE de forma predeterminada y que no necesitamos usar.
1 |
|
2 |
using System; |
3 |
|
4 |
public partial class _Default : System.Web.UI.Page { |
5 |
protected void Page_Load(object sender, EventArgs e) { |
6 |
|
7 |
}
|
8 |
|
9 |
protected void btnAddShoes_Click(object sender, EventArgs e) { |
10 |
// Add product 1 to the shopping cart
|
11 |
ShoppingCart.Instance.AddItem(1); |
12 |
|
13 |
// Redirect the user to view their shopping cart
|
14 |
Response.Redirect("ViewCart.aspx"); |
15 |
}
|
16 |
|
17 |
protected void btnAddShirt_Click(object sender, EventArgs e) { |
18 |
ShoppingCart.Instance.AddItem(2); |
19 |
Response.Redirect("ViewCart.aspx"); |
20 |
}
|
21 |
|
22 |
protected void btnAddPants_Click(object sender, EventArgs e) { |
23 |
ShoppingCart.Instance.AddItem(3); |
24 |
Response.Redirect("ViewCart.aspx"); |
25 |
}
|
26 |
|
27 |
}
|
Desarrollar la página del carrito de compras


Finalmente, lo que hemos estado preparando todo el tiempo: ¡el carrito de compras! Veamos primero ViewCart.aspx y lo explicaré después de eso.
1 |
|
2 |
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ViewCart.aspx.cs" Inherits="ViewCart" %> |
3 |
|
4 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5 |
|
6 |
<html xmlns="http://www.w3.org/1999/xhtml"> |
7 |
<head runat="server"> |
8 |
<title>Shopping Cart</title> |
9 |
<link href="Styles/StyleSheet.css" rel="stylesheet" type="text/css" /> |
10 |
</head>
|
11 |
<body>
|
12 |
|
13 |
<form id="form1" runat="server"> |
14 |
<div class="container"> |
15 |
<h1>Shopping Cart</h1> |
16 |
<a href="Default.aspx">< Back to Products</a> |
17 |
|
18 |
<br /><br /> |
19 |
<asp:GridView runat="server" ID="gvShoppingCart" AutoGenerateColumns="false" EmptyDataText="There is nothing in your shopping cart." GridLines="None" Width="100%" CellPadding="5" ShowFooter="true" DataKeyNames="ProductId" OnRowDataBound="gvShoppingCart_RowDataBound" OnRowCommand="gvShoppingCart_RowCommand"> |
20 |
<HeaderStyle HorizontalAlign="Left" BackColor="#3D7169" ForeColor="#FFFFFF" /> |
21 |
<FooterStyle HorizontalAlign="Right" BackColor="#6C6B66" ForeColor="#FFFFFF" /> |
22 |
<AlternatingRowStyle BackColor="#F8F8F8" /> |
23 |
<Columns>
|
24 |
|
25 |
<asp:BoundField DataField="Description" HeaderText="Description" /> |
26 |
<asp:TemplateField HeaderText="Quantity"> |
27 |
<ItemTemplate>
|
28 |
<asp:TextBox runat="server" ID="txtQuantity" Columns="5" Text='<%# Eval("Quantity") %>'></asp:TextBox><br /> |
29 |
<asp:LinkButton runat="server" ID="btnRemove" Text="Remove" CommandName="Remove" CommandArgument='<%# Eval("ProductId") %>' style="font-size:12px;"></asp:LinkButton> |
30 |
|
31 |
</ItemTemplate>
|
32 |
</asp:TemplateField>
|
33 |
<asp:BoundField DataField="UnitPrice" HeaderText="Price" ItemStyle-HorizontalAlign="Right" HeaderStyle-HorizontalAlign="Right" DataFormatString="{0:C}" /> |
34 |
<asp:BoundField DataField="TotalPrice" HeaderText="Total" ItemStyle-HorizontalAlign="Right" HeaderStyle-HorizontalAlign="Right" DataFormatString="{0:C}" /> |
35 |
</Columns>
|
36 |
</asp:GridView>
|
37 |
|
38 |
<br /> |
39 |
<asp:Button runat="server" ID="btnUpdateCart" Text="Update Cart" OnClick="btnUpdateCart_Click" /> |
40 |
</div>
|
41 |
</form>
|
42 |
</body>
|
43 |
</html>
|
El control GridView es un control poderoso que puede parecer complicado al principio. No discutiré los elementos de estilo porque se explican por sí mismos. (Hay algunos principios aquí que no voy a explicar en profundidad. Sólo voy a tratar de transmitir la idea principal). Vamos a descomponerlo.
- Si le damos a GridView un ID, podremos acceder a GridView desde el código subyacente con ese ID.
1
ID="gvShoppingCart"
- GridView generará automáticamente columnas y nombres de columnas a partir de los datos que suministramos, a menos que específicamente lo indiquemos.
1
AutoGenerateColumns="false"
- Podemos decirle a GridView qué mostrar en caso de que no lo suministremos.
1
EmptyDataText="There is nothing in your shopping cart."
- Queremos mostrar el pie de página para que podamos mostrar el precio total.
1
ShowFooter="true"
- Será bueno para nosotros tener una matriz de ProductIds indexados por el índice de la fila cuando estemos actualizando la cantidad de un artículo del carrito en el código subyacente. Esto hará eso por nosotros:
1
DataKeyNames="ProductId"
- Necesitamos eventos para responder a dos eventos: RowDataBound y RowCommand. Básicamente, RowDataBound se activa cuando el GridView toma una fila de nuestros datos y los agrega a la tabla. Solo estamos usando este evento para responder al pie de página que se está enlazando para que podamos personalizar lo que queremos que se muestre allí. RowCommand se activa cuando se hace clic en un enlace o botón desde dentro de GridView. En este caso, es el enlace "Eliminar".
1
OnRowDataBound="gvShoppingCart_RowDataBound" OnRowCommand="gvShoppingCart_RowCommand"
Ahora hablemos de las columnas. Aquí definimos las columnas y el GridView tomará cada fila de los datos que suministramos y asignaremos los datos de esa fila a la columna en la que deberían aparecer. La columna más simple es el BoundField. En nuestro caso, buscará una propiedad "Description" en nuestro objeto CartItem y la mostrará en la primera columna. El encabezado de esa columna también mostrará la descripción: "Description".
Necesitábamos la cantidad para mostrar dentro de un cuadro de texto en lugar de solo mostrarlo como texto, así que usamos TemplateField. El TemplateField te permite poner lo que quieras en esa columna. Si necesitas algunos datos de la fila, simplemente inserta <%# Eval("PropertyName") %>. El LinkButton que colocamos en nuestro TemplateField tiene un CommandName y un CommandArgument, los cuales se pasarán a nuestro controlador de eventos RowCommand de GridView.
Lo último que vale la pena mencionar aquí es que los dos últimos BoundFields tienen un DataFormatString especificado. Esta es solo una de las muchas cadenas de formato que proporciona ASP.NET. Éste da formato al número como moneda. Consulta la documentación de Microsoft para otros formato de cadenas.
Ahora podemos mirar la página de código subyacente. He proporcionado muchos comentarios aquí para describir lo que está sucediendo.
El resultado final:
¡Ahora tenemos un buen carrito de compras!


También te puede gustar...
Cómo buscar en un sitio web usando ASP.NET 3.5 - Screencast
1 de octubre en Screencasts por Jeffrey Way
Me complace decir que hoy, estamos publicando nuestro primer artículo en ASP.NET. En este Screencast, te mostraré cómo implementar una funcionalidad de búsqueda simple en tu sitio web personal. Revisaremos muchas de las nuevas características de ASP.NET 3.5, como LINQ y muchos de los controles AJAX que se suministran con Visual Studio/Web Developer.
- Suscríbete a la fuente RSS de NETTUTS para obtener más información y artículos de desarrollo web diariamente.





56