Share via


Teil 7: Hinzufügen von Funktionen

von Joe Stagner

Tailspin Spyworks zeigt, wie einfach es ist, leistungsstarke, skalierbare Anwendungen für die .NET-Plattform zu erstellen. Es zeigt, wie Sie die großartigen neuen Features in ASP.NET 4 verwenden, um einen Online-Shop zu erstellen, einschließlich Shopping, Checkout und Verwaltung.

In dieser Tutorialreihe werden alle Schritte zum Erstellen der Tailspin Spyworks-Beispielanwendung beschrieben. Teil 7 fügt zusätzliche Funktionen hinzu, z. B. Kontoüberprüfungen, Produktbewertungen und Benutzersteuerelemente "Beliebte Elemente" und "auch gekaufte" Benutzersteuerelemente.

Hinzufügen von Funktionen

Obwohl Benutzer unseren Katalog durchsuchen, Artikel in ihrem Warenkorb platzieren und den Checkout-Prozess abschließen können, gibt es eine Reihe von unterstützenden Funktionen, die wir zur Verbesserung unserer Website einschließen werden.

  1. Kontoüberprüfung (Bestellungen auflisten und Details anzeigen.)
  2. Fügen Sie der Startseite kontextspezifische Inhalte hinzu.
  3. Fügen Sie ein Feature hinzu, mit dem Benutzer die Produkte im Katalog überprüfen können.
  4. Erstellen Sie ein Benutzersteuerelement, um beliebte Elemente anzuzeigen, und platzieren Sie dieses Steuerelement auf der Startseite.
  5. Erstellen Sie ein Benutzersteuerelement "Auch gekauft", und fügen Sie es der Produktdetailseite hinzu.
  6. Fügen Sie eine Kontaktseite hinzu.
  7. Fügen Sie eine Infoseite hinzu.
  8. Globaler Fehler

Kontoüberprüfung

Erstellen Sie im Ordner "Konto" zwei ASPX-Seiten mit dem Namen OrderList.aspx und orderDetails.aspx.

OrderList.aspx nutzt die GridView- und EntityDataSource-Steuerelemente wie zuvor.

<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 wählt Datensätze aus der Tabelle Orders aus, die nach dem Benutzernamen gefiltert wird (siehe WhereParameter), den wir in einer Sitzungsvariable festlegen, wenn sich der Benutzer anmeldet.

Beachten Sie auch die folgenden Parameter im HyperlinkField der GridView:

DataNavigateUrlFields="OrderID" DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}"

Diese geben den Link zur Ansicht Bestelldetails für jedes Produkt an, das das Feld OrderID als QueryString-Parameter für die Seite "OrderDetails.aspx" angibt.

OrderDetails.aspx

Wir verwenden ein EntityDataSource-Steuerelement für den Zugriff auf die Orders und eine FormView zum Anzeigen der Order-Daten und eine andere EntityDataSource mit einer GridView, um alle Zeilenelemente der Bestellung anzuzeigen.

<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>

In der Code Behind-Datei (OrderDetails.aspx.cs) haben wir zwei kleine Housekeeping-Bits.

Zunächst müssen wir sicherstellen, dass OrderDetails immer eine OrderId erhält.

protected void Page_Load(object sender, EventArgs e)
{
  if (String.IsNullOrEmpty(Request.QueryString["OrderId"]))
     {
     Response.Redirect("~/Account/OrderList.aspx");
     }
}

Außerdem müssen wir die Auftragssumme aus den Zeilenpositionen berechnen und anzeigen.

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");
   }
}

Startseite

Fügen Wir der Seite Default.aspx statische Inhalte hinzu.

Zuerst erstelle ich einen Ordner "Inhalt" und darin einen Ordner Images (und ich schließe ein Bild ein, das auf der Startseite verwendet werden soll.)

Fügen Sie im unteren Platzhalter der Seite Default.aspx das folgende Markup hinzu.

<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>

Produktbewertungen

Zunächst fügen wir eine Schaltfläche mit einem Link zu einem Formular hinzu, mit dem wir eine Produktbewertung eingeben können.

<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>

Screenshot: Linkspeicherort

Beachten Sie, dass wir die ProductID in der Abfragezeichenfolge übergeben.

Als Nächstes fügen wir die Seite "ReviewAdd.aspx" hinzu.

Auf dieser Seite wird das ASP.NET AJAX Control Toolkit verwendet. Wenn Sie dies noch nicht getan haben, können Sie es von DevExpress herunterladen, und es gibt hier https://www.asp.net/learn/ajax-videos/video-76.aspxAnleitungen zum Einrichten des Toolkits für die Verwendung mit Visual Studio.

Ziehen Sie im Entwurfsmodus Steuerelemente und Validatoren aus der Toolbox, und erstellen Sie ein Formular wie das folgende.

Screenshot des Formulars

Das Markup sieht in etwa wie folgt aus.

<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>

Da wir nun Bewertungen eingeben können, können Sie diese Bewertungen auf der Produktseite anzeigen.

Fügen Sie dieses Markup der Seite ProductDetails.aspx hinzu.

<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>

Wenn Sie unsere Anwendung jetzt ausführen und zu einem Produkt navigieren, werden die Produktinformationen einschließlich Kundenbewertungen angezeigt.

Screenshot: Kundenrezensionen

Steuerelement "Beliebte Elemente" (Erstellen von Benutzersteuerelementen)

Um den Umsatz auf Ihrer Website zu steigern, fügen wir einige Features zu beliebten oder verwandten Produkten hinzu.

Die erste dieser Features ist eine Liste der beliebtesten Produkte in unserem Produktkatalog.

Wir erstellen ein "Benutzersteuerelement", um die meistverkauften Elemente auf der Startseite unserer Anwendung anzuzeigen. Da es sich um ein Steuerelement handelt, können wir es auf einer beliebigen Seite verwenden, indem wir das Steuerelement im Visual Studio-Designer einfach auf eine beliebige Seite ziehen und ablegen.

Klicken Sie im Projektmappen-Explorer von Visual Studio mit der rechten Maustaste auf den Projektmappennamen, und erstellen Sie ein neues Verzeichnis mit dem Namen "Controls". Dies ist zwar nicht erforderlich, aber wir helfen, unser Projekt zu organisieren, indem wir alle Benutzersteuerelemente im Verzeichnis "Controls" erstellen.

Klicken Sie mit der rechten Maustaste auf den Ordner steuerelemente, und wählen Sie "Neues Element" aus:

Screenshot: Auswahl neuer Elemente

Geben Sie einen Namen für unser Steuerelement "PopularItems" an. Beachten Sie, dass die Dateierweiterung für Benutzersteuerelemente .ascx und nicht ASPX ist.

Unser Benutzersteuerelement "Beliebte Elemente" wird wie folgt definiert.

<%@ 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>

Hier verwenden wir eine Methode, die wir in dieser Anwendung noch nicht verwendet haben. Wir verwenden das Repeatersteuerelement, und anstatt ein Datenquellensteuerelement zu verwenden, binden wir das Repeater-Steuerelement an die Ergebnisse einer LINQ to Entities Abfrage.

Im Code hinter unserem Steuerelement führen wir dies wie folgt aus.

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);
      }
    }
}

Beachten Sie auch diese wichtige Zeile oben im Markup des Steuerelements.

<%@ OutputCache Duration="3600" VaryByParam="None" %>

Da sich die beliebtesten Elemente nicht von Minute zu Minute ändern, können wir eine schmerzende Direktive hinzufügen, um die Leistung unserer Anwendung zu verbessern. Diese Anweisung bewirkt, dass der Steuerelementcode nur ausgeführt wird, wenn die zwischengespeicherte Ausgabe des Steuerelements abläuft. Andernfalls wird die zwischengespeicherte Version der Ausgabe des Steuerelements verwendet.

Jetzt müssen wir nur noch unser neues Steuerelement auf der Seite Default.aspx einschließen.

Verwenden Sie drag and drop, um eine instance des Steuerelements in der geöffneten Spalte des Standardformulars zu platzieren.

Screenshot: Position einer instance des Steuerelements

Wenn wir nun unsere Anwendung ausführen, werden auf der Startseite die beliebtesten Elemente angezeigt.

Screenshot, der zeigt, wie auf der Startseite die beliebtesten Elemente angezeigt werden.

Steuerelement "Auch gekauft" (Benutzersteuerelemente mit Parametern)

Das zweite Benutzersteuerelement, das wir erstellen, führt den vorschlagsabhängigen Verkauf auf die nächste Ebene, indem es Kontextspezifität hinzufügt.

Die Logik zum Berechnen der wichtigsten "Auch gekauften" Elemente ist nicht trivial.

Unser Steuerelement "Auch gekauft" wählt die Datensätze OrderDetails (zuvor erworben) für die aktuell ausgewählte ProductID aus und greift die OrderIDs für jede eindeutige Bestellung ab, die gefunden wird.

Dann wählen wir die Produkte aus all diesen Bestellungen aus und summieren die gekauften Mengen. Wir sortieren die Produkte nach dieser Mengensumme und zeigen die ersten fünf Elemente an.

Angesichts der Komplexität dieser Logik implementieren wir diesen Algorithmus als gespeicherte Prozedur.

Die T-SQL-Datei für die gespeicherte Prozedur lautet wie folgt.

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

Beachten Sie, dass diese gespeicherte Prozedur (SelectPurchasedWithProducts) in der Datenbank vorhanden war, als wir sie in unsere Anwendung eingeschlossen haben, und als wir das Entitätsdatenmodell generiert haben, haben wir angegeben, dass das Entitätsdatenmodell zusätzlich zu den benötigten Tabellen und Ansichten diese gespeicherte Prozedur enthalten sollte.

Um über das Entitätsdatenmodell auf die gespeicherte Prozedur zuzugreifen, müssen wir die Funktion importieren.

Doppelklicken Sie auf das Entitätsdatenmodell in der Explorer Lösungen, um es im Designer zu öffnen und den Modellbrowser zu öffnen, klicken Sie dann mit der rechten Maustaste in den Designer, und wählen Sie "Funktionsimport hinzufügen" aus.

Screenshot, der zeigt, wo Sie Funktionsimport hinzufügen auswählen.

Dadurch wird dieses Dialogfeld geöffnet.

Screenshot des geöffneten Dialogfelds

Füllen Sie die Felder aus, wie Sie oben sehen, und wählen Sie "SelectPurchasedWithProducts" aus, und verwenden Sie den Prozedurnamen für den Namen unserer importierten Funktion.

Klicken Sie auf "OK".

Nachdem wir dies getan haben, können wir einfach für die gespeicherte Prozedur programmieren, wie jedes andere Element im Modell.

Erstellen Sie daher in unserem Ordner "Controls" ein neues Benutzersteuerelement mit dem Namen AlsoPurchased.ascx.

Das Markup für dieses Steuerelement sieht dem PopularItems-Steuerelement sehr vertraut aus.

<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>

Der bemerkenswerte Unterschied besteht darin, dass die Ausgabe nicht zwischengespeichert wird, da sich die zu rendernden Elemente je nach Produkt unterscheiden.

Die ProductId ist eine "Eigenschaft" für das Steuerelement.

private int _ProductId;

public int ProductId
{
get { return _ProductId ; }
set { _ProductId = Convert.ToInt32(value); }
}

Im PreRender-Ereignishandler des Steuerelements haben wir drei Schritte ausgeführt.

  1. Stellen Sie sicher, dass die ProductID festgelegt ist.
  2. Überprüfen Sie, ob es Produkte gibt, die mit dem aktuellen gekauft wurden.
  3. Geben Sie einige Elemente aus, wie in #2 festgelegt.

Beachten Sie, wie einfach es ist, die gespeicherte Prozedur über das Modell aufzurufen.

//--------------------------------------------------------------------------------------+
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();
     }
}

Nachdem wir festgestellt haben, dass ES "AUCH gekauft" gibt, können wir den Repeater einfach an die von der Abfrage zurückgegebenen Ergebnisse binden.

//-------------------------------------------------------------------------------------+
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);
          }
        }
}

Wenn es keine "auch gekauften" Artikel gab, zeigen wir einfach andere beliebte Elemente aus unserem Katalog an.

//--------------------------------------------------------------------------------------+
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);
      }
    }
}

Um die Elemente "Auch gekauft" anzuzeigen, öffnen Sie die Seite ProductDetails.aspx, und ziehen Sie das AlsoPurchased-Steuerelement aus dem Explorer Lösungen, sodass es an dieser Position im Markup angezeigt wird.

<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>

Dadurch wird ein Verweis auf das Steuerelement oben auf der Seite ProductDetails erstellt.

<%@ Register src="Controls/AlsoPurchased.ascx" tagname="AlsoPurchased" tagprefix="uc1" %>

Da das AlsoPurchased-Benutzersteuerelement eine ProductId-Nummer erfordert, legen wir die ProductID-Eigenschaft unseres Steuerelements mithilfe einer Eval-Anweisung für das aktuelle Datenmodellelement der Seite fest.

Screenshot: Hervorhebung des Produkt-I D.

Wenn wir jetzt erstellen und ausführen und zu einem Produkt navigieren, werden die Elemente "Auch gekauft" angezeigt.

Screenshot: Elemente, die ebenfalls gekauft wurden