Parte 7: Agregar características
por Joe Stagner
Tailspin Spyworks muestra cómo es extraordinariamente simple crear aplicaciones eficaces y escalables para la plataforma .NET. Muestra cómo usar las excelentes características nuevas de ASP.NET 4 para crear una tienda en línea, como compras, desprotección y administración.
En esta serie de tutoriales se detallan todos los pasos realizados para compilar la aplicación de ejemplo Tailspin Spyworks. La parte 7 agrega características adicionales, como la revisión de cuentas, las revisiones de productos y los controles de usuario "artículos populares" y "también comprados".
Agregar características
Aunque los usuarios pueden examinar nuestro catálogo, colocar elementos en su carro de la compra y completar el proceso de compra, hay una serie de características auxiliares que incluiremos para mejorar nuestro sitio.
- Revisión de la cuenta (Enumerar pedidos realizados y ver los detalles.)
- Agregue contenido específico del contexto a la página principal.
- Agregue una característica para permitir que los usuarios Revisen los productos del catálogo.
- Cree un control de usuario para mostrar elementos populares y colocar ese control en la página principal.
- Cree un control de usuario "También comprado" y agréguelo a la página de detalles del producto.
- Agregue una página de contacto.
- Agregue una página Acerca de.
- Global Error
Revisión de la cuenta
En la carpeta "Cuenta", cree dos páginas .aspx una denominada OrderList.aspx y la otra denominada OrderDetails.aspx
OrderList.aspx aprovechará los controles GridView y EntityDataSource tanto como antes.
<div class="ContentHead">Order History</div><br />
<asp:GridView ID="GridView_OrderList" runat="server" AllowPaging="True"
ForeColor="#333333" GridLines="None" CellPadding="4" Width="100%"
AutoGenerateColumns="False" DataKeyNames="OrderID"
DataSourceID="EDS_Orders" AllowSorting="True" ViewStateMode="Disabled" >
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:BoundField DataField="OrderID" HeaderText="OrderID" ReadOnly="True"
SortExpression="OrderID" />
<asp:BoundField DataField="CustomerName" HeaderText="Customer"
SortExpression="CustomerName" />
<asp:BoundField DataField="OrderDate" HeaderText="Order Date"
SortExpression="OrderDate" />
<asp:BoundField DataField="ShipDate" HeaderText="Ship Date"
SortExpression="ShipDate" />
<asp:HyperLinkField HeaderText="Show Details" Text="Show Details"
DataNavigateUrlFields="OrderID"
DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}" />
</Columns>
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
<SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" />
<SortedAscendingCellStyle BackColor="#FDF5AC" />
<SortedAscendingHeaderStyle BackColor="#4D0000" />
<SortedDescendingCellStyle BackColor="#FCF6C0" />
<SortedDescendingHeaderStyle BackColor="#820000" />
<SortedAscendingCellStyle BackColor="#FDF5AC"></SortedAscendingCellStyle>
<SortedAscendingHeaderStyle BackColor="#4D0000"></SortedAscendingHeaderStyle>
<SortedDescendingCellStyle BackColor="#FCF6C0"></SortedDescendingCellStyle>
<SortedDescendingHeaderStyle BackColor="#820000"></SortedDescendingHeaderStyle>
</asp:GridView>
<asp:EntityDataSource ID="EDS_Orders" runat="server" EnableFlattening="False"
AutoGenerateWhereClause="True"
Where=""
OrderBy="it.OrderDate DESC"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EntitySetName="Orders" >
<WhereParameters>
<asp:SessionParameter Name="CustomerName" SessionField="UserName" />
</WhereParameters>
</asp:EntityDataSource>
EntityDataSource selecciona los registros de la tabla Orders filtrados en UserName (vea WhereParameter) que se establece en una variable de sesión cuando el usuario inicia sesión.
Tenga en cuenta también estos parámetros en HyperlinkField de GridView:
DataNavigateUrlFields="OrderID" DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}"
Especifican el vínculo a la vista Detalles del pedido para cada producto que especifica el campo OrderID como parámetro QueryString en la página de OrderDetails.aspx.
OrderDetails.aspx
Usaremos un control EntityDataSource para tener acceso a Orders y FormView para mostrar los datos Order y otro EntityDataSource con GridView para mostrar todos los elementos de línea del pedido.
<asp:FormView ID="FormView1" runat="server" CellPadding="4"
DataKeyNames="OrderID"
DataSourceID="EDS_Order" ForeColor="#333333" Width="250px">
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<ItemTemplate>
OrderID : <%# Eval("OrderID") %><br />
CustomerName : <%# Eval("CustomerName") %><br />
Order Date : <%# Eval("OrderDate") %><br />
Ship Date : <%# Eval("ShipDate") %><br />
</ItemTemplate>
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
</asp:FormView>
<asp:EntityDataSource ID="EDS_Order" runat="server" EnableFlattening="False"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EntitySetName="Orders"
AutoGenerateWhereClause="True"
Where=""
EntityTypeFilter="" Select="">
<WhereParameters>
<asp:QueryStringParameter Name="OrderID" QueryStringField="OrderID" Type="Int32" />
</WhereParameters>
</asp:EntityDataSource>
<asp:GridView ID="GridView_OrderDetails" runat="server"
AutoGenerateColumns="False"
DataKeyNames="ProductID,UnitCost,Quantity"
DataSourceID="EDS_OrderDetails"
CellPadding="4" GridLines="Vertical" CssClass="CartListItem"
onrowdatabound="MyList_RowDataBound" ShowFooter="True"
ViewStateMode="Disabled">
<AlternatingRowStyle CssClass="CartListItemAlt" />
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="Product ID" ReadOnly="True"
SortExpression="ProductID" />
<asp:BoundField DataField="ModelNumber" HeaderText="Model Number"
SortExpression="ModelNumber" />
<asp:BoundField DataField="ModelName" HeaderText="Model Name"
SortExpression="ModelName" />
<asp:BoundField DataField="UnitCost" HeaderText="Unit Cost" ReadOnly="True"
SortExpression="UnitCost" DataFormatString="{0:c}" />
<asp:BoundField DataField="Quantity" HeaderText="Quantity" ReadOnly="True"
SortExpression="Quantity" />
<asp:TemplateField>
<HeaderTemplate>Item Total</HeaderTemplate>
<ItemTemplate>
<%# (Convert.ToDouble(Eval("Quantity")) * Convert.ToDouble(Eval("UnitCost")))%>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle CssClass="CartListFooter"/>
<HeaderStyle CssClass="CartListHead" />
</asp:GridView>
<asp:EntityDataSource ID="EDS_OrderDetails" runat="server"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EnableFlattening="False"
EntitySetName="VewOrderDetails"
AutoGenerateWhereClause="True"
Where="">
<WhereParameters>
<asp:QueryStringParameter Name="OrderID" QueryStringField="OrderID" Type="Int32" />
</WhereParameters>
</asp:EntityDataSource>
En el archivo de código subyacente (OrderDetails.aspx.cs) tenemos dos bits pequeños de limpieza.
En primer lugar, debemos asegurarnos de que OrderDetails siempre obtiene un OrderId.
protected void Page_Load(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(Request.QueryString["OrderId"]))
{
Response.Redirect("~/Account/OrderList.aspx");
}
}
También es necesario calcular y mostrar el total del pedido a partir de los elementos de línea.
decimal _CartTotal = 0;
protected void MyList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
TailspinSpyworks.Data_Access.VewOrderDetail myCart = new
Data_Access.VewOrderDetail();
myCart = (TailspinSpyworks.Data_Access.VewOrderDetail)e.Row.DataItem;
_CartTotal += Convert.ToDecimal(myCart.UnitCost * myCart.Quantity);
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[5].Text = "Total: " + _CartTotal.ToString("C");
}
}
Página principal
Vamos a agregar contenido estático a la página de Default.aspx.
En primer lugar, crearé una carpeta "Contenido" y dentro de ella una carpeta Imágenes (y incluiré una imagen que se usará en la página principal).
En el marcador de posición inferior de la página Default.aspx, agregue el marcado siguiente.
<h2>
<asp:LoginView ID="LoginView_VisitorGreeting" runat="server">
<AnonymousTemplate>
Welcome to the Store !
</AnonymousTemplate>
<LoggedInTemplate>
Hi <asp:LoginName ID="LoginName_Welcome" runat="server" />. Thanks for coming back.
</LoggedInTemplate>
</asp:LoginView>
</h2>
<p><strong>TailSpin Spyworks</strong> demonstrates how extraordinarily simple it is to create powerful, scalable applications for the .NET platform. </p>
<table>
<tr>
<td>
<h3>Some Implementation Features.</h3>
<ul>
<li><a href="#">CSS Based Design.</a></li>
<li><a href="#">Data Access via Linq to Entities.</a></li>
<li><a href="#">MasterPage driven design.</a></li>
<li><a href="#">Modern ASP.NET Controls User.</a></li>
<li><a href="#">Integrated Ajac Control Toolkit Editor.</a></li>
</ul>
</td>
<td>
<img src="Content/Images/SampleProductImage.gif" alt=""/>
</td>
</tr>
</table>
<table>
<tr>
<td colspan="2"><hr /></td>
</tr>
<tr>
<td>
<!-- Popular Items -->
</td>
<td>
<center><h3>Ecommerce the .NET 4 Way</h3></center>
<blockquote>
<p>
ASP.NET offers web developers the benefit of more that a decade of innovation.
This demo leverages many of the latest features of ASP.NET development to
illustrate really simply building rich web applications with ASP.NET can be.
For more information about build web applications with ASP.NET please visit the
community web site at www.asp.net
</p>
</blockquote>
</td>
</tr>
</table>
<h3>Spyworks Event Calendar</h3>
<table>
<tr class="rowH">
<th>Date</th>
<th>Title</th>
<th>Description</th>
</tr>
<tr class="rowA">
<td>June 01, 2011</td>
<td>Sed vestibulum blandit</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
<tr class="rowB">
<td>November 28, 2011</td>
<td>Spyworks Product Demo</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
<tr class="rowA">
<td>November 23, 2011</td>
<td>Spyworks Product Demo</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
<tr class="rowB">
<td>November 21, 2011</td>
<td>Spyworks Product Demo</td>
<td>
Come and check out demos of all the newest Tailspin Spyworks products and experience
them hands on.
</td>
</tr>
</table>
Revisiones de productos
En primer lugar, agregaremos un botón con un vínculo a un formulario que podemos usar para escribir una revisión del producto.
<div class="SubContentHead">Reviews</div><br />
<a id="ReviewList_AddReview" href="ReviewAdd.aspx?productID=<%# Eval("ProductID") %>">
<img id="Img2" runat="server"
src="~/Styles/Images/review_this_product.gif" alt="" />
</a>
Tenga en cuenta que estamos pasando ProductID en la cadena de consulta.
A continuación, vamos a agregar la página denominada ReviewAdd.aspx
Esta página usará el kit de herramientas de control de AJAX de ASP.NET. Si aún no lo ha hecho, puede descargarlo desde DevExpress y hay instrucciones para configurar el kit de herramientas para su uso con Visual Studio aquí https://www.asp.net/learn/ajax-videos/video-76.aspx.
En el modo de diseño, arrastre controles y validadores desde el cuadro de herramientas y cree un formulario como el siguiente.
El marcado tendrá un aspecto similar al siguiente.
<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</asp:ToolkitScriptManager>
<div class="ContentHead">Add Review - <asp:label id="ModelName" runat="server" /></div>
<div>
<span class="NormalBold">Name</span><br />
<asp:TextBox id="Name" runat="server" Width="400px" /><br />
<asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator1"
ControlToValidate="Name"
Display="Dynamic"
CssClass="ValidationError"
ErrorMessage="'Name' must not be left blank." /><br />
<span class="NormalBold">Email</span><br />
<asp:TextBox id="Email" runat="server" Width="400px" /><br />
<asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator2"
ControlToValidate="Email" Display="Dynamic"
CssClass="ValidationError"
ErrorMessage="'Email' must not be left blank." />
<br /><hr /><br />
<span class="NormalBold">Rating</span><br /><br />
<asp:RadioButtonList ID="Rating" runat="server">
<asp:ListItem value="5" selected="True"
Text='<img src="Styles/Images/reviewrating5.gif" alt=""> (Five Stars) ' />
<asp:ListItem value="4" selected="True"
Text='<img src="Styles/Images/reviewrating4.gif" alt=""> (Four Stars) ' />
<asp:ListItem value="3" selected="True"
Text='<img src="Styles/Images/reviewrating3.gif" alt=""> (Three Stars) ' />
<asp:ListItem value="2" selected="True"
Text='<img src="Styles/Images/reviewrating2.gif" alt=""> (Two Stars) ' />
<asp:ListItem value="1" selected="True"
Text='<img src="Styles/Images/reviewrating1.gif" alt=""> (One Stars) ' />
</asp:RadioButtonList>
<br /><hr /><br />
<span class="NormalBold">Comments</span><br />
<cc1:Editor ID="UserComment" runat="server" />
<asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator3"
ControlToValidate="UserComment" Display="Dynamic"
CssClass="ValidationError"
ErrorMessage="Please enter your comment." /><br /><br />
<asp:ImageButton ImageURL="Styles/Images/submit.gif" runat="server"
id="ReviewAddBtn" onclick="ReviewAddBtn_Click" />
<br /><br /><br />
</div>
Ahora que podemos escribir revisiones, permite mostrar esas revisiones en la página del producto.
Agregue este marcado a la página de ProductDetails.aspx.
<asp:ListView ID="ListView_Comments" runat="server"
DataKeyNames="ReviewID,ProductID,Rating" DataSourceID="EDS_CommentsList">
<ItemTemplate>
<tr>
<td><%# Eval("CustomerName") %></td>
<td>
<img src='Styles/Images/ReviewRating_d<%# Eval("Rating") %>.gif' alt="">
<br />
</td>
<td>
<%# Eval("Comments") %>
</td>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr>
<td><%# Eval("CustomerName") %></td>
<td>
<img src='Styles/Images/ReviewRating_da<%# Eval("Rating") %>.gif' alt="">
<br />
</td>
<td><%# Eval("Comments") %></td>
</tr>
</AlternatingItemTemplate>
<EmptyDataTemplate>
<table runat="server">
<tr><td>There are no reviews yet for this product.</td></tr>
</table>
</EmptyDataTemplate>
<LayoutTemplate>
<table runat="server">
<tr runat="server">
<td runat="server">
<table ID="itemPlaceholderContainer" runat="server" border="1">
<tr runat="server">
<th runat="server">Customer</th>
<th runat="server">Rating</th>
<th runat="server">Comments</th>
</tr>
<tr ID="itemPlaceholder" runat="server"></tr>
</table>
</td>
</tr>
<tr runat="server">
<td runat="server">
<asp:DataPager ID="DataPager1" runat="server">
<Fields>
<asp:NextPreviousPagerField ButtonType="Button"
ShowFirstPageButton="True"
ShowLastPageButton="True" />
</Fields>
</asp:DataPager>
</td>
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
<asp:EntityDataSource ID="EDS_CommentsList" runat="server" EnableFlattening="False"
AutoGenerateWhereClause="True"
EntityTypeFilter=""
Select="" Where=""
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EntitySetName="Reviews">
<WhereParameters>
<asp:QueryStringParameter Name="ProductID" QueryStringField="productID"
Type="Int32" />
</WhereParameters>
</asp:EntityDataSource>
La ejecución de la aplicación ahora y la navegación a un producto muestra la información del producto, incluidas las revisiones de los clientes.
Control Elementos populares (crear controles de usuario)
Para aumentar las ventas en su sitio web, agregaremos un par de características a "venta sugerida" popular o productos relacionados.
La primera de estas características será una lista del producto más popular en nuestro catálogo de productos.
Crearemos un "Control de usuario" para mostrar los artículos más vendidos en la página principal de nuestra aplicación. Dado que se trata de un control, podemos usarlo en cualquier página arrastrando y colocando el control en el diseñador de Visual Studio en cualquier página que nos guste.
En el explorador de soluciones de Visual Studio, haga clic con el botón derecho en el nombre de la solución y cree un directorio denominado "Controls". Aunque no es necesario hacerlo, ayudaremos a mantener el proyecto organizado creando todos nuestros controles de usuario en el directorio "Controls".
Haga clic con el botón derecho en la carpeta controls y elija "Nuevo elemento":
Especifique un nombre para el control "PopularItems". Tenga en cuenta que la extensión de archivo para los controles de usuario es .ascx no .aspx.
Nuestro control de usuario Elementos populares se definirá de la manera siguiente.
<%@ OutputCache Duration="3600" VaryByParam="None" %>
<div class="MostPopularHead">Our most popular items this week</div>
<div id="PanelPopularItems" runat="server">
<asp:Repeater ID="RepeaterItemsList" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<a class='MostPopularItemText'
href='ProductDetails.aspx?productID=<%# Eval("ProductId") %>'>
<%# Eval("ModelName") %></a><br />
</ItemTemplate>
<FooterTemplate></FooterTemplate>
</asp:Repeater>
</div>
Aquí vamos a usar un método que aún no hemos usado en esta aplicación. Estamos usando el control repetir y, en lugar de usar un control de origen de datos, estamos enlazando el control Repetir a los resultados de una consulta LINQ to Entities.
En el código subyacente de nuestro control, lo hacemos de la siguiente manera.
using TailspinSpyworks.Data_Access;
protected void Page_Load(object sender, EventArgs e)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var query = (from ProductOrders in db.OrderDetails
join SelectedProducts in db.Products on ProductOrders.ProductID
equals SelectedProducts.ProductID
group ProductOrders by new
{
ProductId = SelectedProducts.ProductID,
ModelName = SelectedProducts.ModelName
} into grp
select new
{
ModelName = grp.Key.ModelName,
ProductId = grp.Key.ProductId,
Quantity = grp.Sum(o => o.Quantity)
} into orderdgrp where orderdgrp.Quantity > 0
orderby orderdgrp.Quantity descending select orderdgrp).Take(5);
RepeaterItemsList.DataSource = query;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Load Popular Items - " +
exp.Message.ToString(), exp);
}
}
}
Tenga en cuenta también esta línea importante en la parte superior del marcado del control.
<%@ OutputCache Duration="3600" VaryByParam="None" %>
Dado que los elementos más populares no cambiarán por minuto a minuto, podemos agregar una directiva de almacenamiento para mejorar el rendimiento de nuestra aplicación. Esta directiva hará que el código de los controles solo se ejecute cuando expire la salida almacenada en caché del control. De lo contrario, se usará la versión almacenada en caché de la salida del control.
Ahora todo lo que tenemos que hacer es incluir nuestro nuevo control en nuestra página de Default.aspx.
Use arrastrar y colocar para colocar una instancia del control en la columna abierta del formulario Predeterminado.
Ahora, cuando ejecutamos nuestra aplicación, la página principal muestra los elementos más populares.
Control "También comprado" (controles de usuario con parámetros)
El segundo control de usuario que crearemos tomará la venta sugerida al siguiente nivel agregando una especificidad del contexto.
La lógica para calcular los elementos principales "También comprados" no es trivial.
Nuestro control "También comprado" seleccionará los registros OrderDetails (comprados previamente) para el ProductID seleccionado actualmente y tomar los OrderIDs para cada pedido único que se encuentre.
A continuación, seleccionaremos los productos de todos esos pedidos y sumaremos las cantidades compradas. Ordenaremos los productos por esa suma de cantidad y mostraremos los cinco primeros artículos.
Dada la complejidad de esta lógica, implementaremos este algoritmo como un procedimiento almacenado.
El T-SQL para el procedimiento almacenado es el siguiente.
ALTER PROCEDURE dbo.SelectPurchasedWithProducts
@ProductID int
AS
SELECT TOP 5
OrderDetails.ProductID,
Products.ModelName,
SUM(OrderDetails.Quantity) as TotalNum
FROM
OrderDetails
INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID
WHERE OrderID IN
(
/* This inner query should retrieve all orders that have contained the productID */
SELECT DISTINCT OrderID
FROM OrderDetails
WHERE ProductID = @ProductID
)
AND OrderDetails.ProductID != @ProductID
GROUP BY OrderDetails.ProductID, Products.ModelName
ORDER BY TotalNum DESC
RETURN
Tenga en cuenta que este procedimiento almacenado (SelectPurchasedWithProducts) existía en la base de datos cuando lo incluimos en nuestra aplicación y cuando se generó el modelo de datos de entidad especificó que, además de las tablas y vistas que necesitamos, el modelo de datos de entidad debe incluir este procedimiento almacenado.
Para acceder al procedimiento almacenado desde Entity Data Model, es necesario importar la función.
Haga doble clic en Entity Data Model (Modelo de datos de entidad) en el Explorador de soluciones para abrirlo en el diseñador y abra el Explorador de modelos y, a continuación, haga clic con el botón derecho en el diseñador y seleccione "Agregar importación de funciones".
Al hacerlo, se abrirá este cuadro de diálogo.
Rellene los campos como se ha mencionado anteriormente, seleccionando "SelectPurchasedWithProducts" y use el nombre del procedimiento para el nombre de nuestra función importada.
Haga clic en "Aceptar".
Una vez hecho esto, simplemente podemos programar con el procedimiento almacenado, ya que podríamos cualquier otro elemento del modelo.
Por lo tanto, en nuestra carpeta "Controles", cree un nuevo control de usuario denominado AlsoPurchased.ascx.
El marcado de este control será muy familiar para el control PopularItems.
<div>
<div class="MostPopularHead">
<asp:Label ID="LabelTitle" runat="server" Text=" Customers who bought this also bought:"></asp:Label></div>
<div id="PanelAlsoBoughtItems" runat="server">
<asp:Repeater ID="RepeaterItemsList" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<a class='MostPopularItemText' href='ProductDetails.aspx?productID=<%# Eval("ProductId") %>'><%# Eval("ModelName") %></a><br />
</ItemTemplate>
<FooterTemplate></FooterTemplate>
</asp:Repeater>
</div>
</div>
La diferencia notable es que no almacena en caché la salida, ya que el elemento que se va a representar será diferente por producto.
ProductId será una "propiedad" para el control.
private int _ProductId;
public int ProductId
{
get { return _ProductId ; }
set { _ProductId = Convert.ToInt32(value); }
}
En el controlador de eventos PreRender del control, hemos hecho tres cosas.
- Asegúrese de que ProductID está establecido.
- Vea si hay algún producto que se haya comprado con el actual.
- Genera algunos elementos como se determina en el número 2.
Tenga en cuenta lo fácil que es llamar al procedimiento almacenado a través del modelo.
//--------------------------------------------------------------------------------------+
protected void Page_PreRender(object sender, EventArgs e)
{
if (_ProductId < 1)
{
// This should never happen but we could expand the use of this control by reducing
// the dependency on the query string by selecting a few RANDOME products here.
Debug.Fail("ERROR : The Also Purchased Control Can not be used without
setting the ProductId.");
throw new Exception("ERROR : It is illegal to load the AlsoPurchased COntrol
without setting a ProductId.");
}
int ProductCount = 0;
using (CommerceEntities db = new CommerceEntities())
{
try
{
var v = db.SelectPurchasedWithProducts(_ProductId);
ProductCount = v.Count();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Retrieve Also Purchased Items - " +
exp.Message.ToString(), exp);
}
}
if (ProductCount > 0)
{
WriteAlsoPurchased(_ProductId);
}
else
{
WritePopularItems();
}
}
Después de determinar que HAY "también comprado" podemos enlazar simplemente el repetidor a los resultados devueltos por la consulta.
//-------------------------------------------------------------------------------------+
private void WriteAlsoPurchased(int currentProduct)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var v = db.SelectPurchasedWithProducts(currentProduct);
RepeaterItemsList.DataSource = v;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Write Also Purchased - " +
exp.Message.ToString(), exp);
}
}
}
Si no hubiera ningún "también comprado" artículos, simplemente mostraremos otros artículos populares de nuestro catálogo.
//--------------------------------------------------------------------------------------+
private void WritePopularItems()
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var query = (from ProductOrders in db.OrderDetails
join SelectedProducts in db.Products on ProductOrders.ProductID
equals SelectedProducts.ProductID
group ProductOrders by new
{
ProductId = SelectedProducts.ProductID,
ModelName = SelectedProducts.ModelName
} into grp
select new
{
ModelName = grp.Key.ModelName,
ProductId = grp.Key.ProductId,
Quantity = grp.Sum(o => o.Quantity)
} into orderdgrp
where orderdgrp.Quantity > 0
orderby orderdgrp.Quantity descending
select orderdgrp).Take(5);
LabelTitle.Text = "Other items you might be interested in: ";
RepeaterItemsList.DataSource = query;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Load Popular Items - " +
exp.Message.ToString(), exp);
}
}
}
Para ver los elementos "También comprados", abra la página ProductDetails.aspx y arrastre el control AlsoPurchased desde el Explorador de soluciones para que aparezca en esta posición en el marcado.
<table border="0">
<tr>
<td>
<img src='Catalog/Images/<%# Eval("ProductImage") %>' border="0"
alt='<%# Eval("ModelName") %>' />
</td>
<td><%# Eval("Description") %><br /><br /><br />
<uc1:AlsoPurchased ID="AlsoPurchased1" runat="server" />
</td>
</tr>
</table>
Si lo hace, creará una referencia al control en la parte superior de la página ProductDetails.
<%@ Register src="Controls/AlsoPurchased.ascx" tagname="AlsoPurchased" tagprefix="uc1" %>
Dado que el control de usuario AlsoPurchased requiere un número ProductId, estableceremos la propiedad ProductID de nuestro control mediante una instrucción Eval en el elemento del modelo de datos actual de la página.
Cuando compilamos y ejecutamos ahora y buscamos un producto, vemos los elementos "También comprados".