第 6 部分:ASP.NET 成員資格
作者 :Joe Stagner
注意
本文撰寫之後,ASP.NET 成員資格提供者已被 ASP.NET 身分識別取代。 強烈建議您將應用程式更新為使用 ASP.NET 身分識別 平臺,而不是本文撰寫時精選的成員資格提供者。 ASP.NET 身分識別的一些優點優於 ASP.NET 成員資格系統,包括 :
- 更好的效能
- 改善擴充性和可測試性
- 支援 OAuth、OpenID Connect 和雙因素驗證
- 宣告型身分識別支援
- 與 ASP.Net Core 的較佳互通性
Tailspin Spyworks 示範如何非常簡單,為 .NET 平臺建立功能強大的可調整應用程式。 它示範如何使用 ASP.NET 4 中的絕佳新功能來建置線上商店,包括購物、結帳和管理。
本教學課程系列詳細說明建置 Tailspin Spyworks 範例應用程式所採取的所有步驟。 第 6 部分會新增 ASP.NET 成員資格。
使用 ASP.NET 成員資格
按一下 [安全性]
請確定我們使用表單驗證。
使用 [建立使用者] 連結來建立幾個使用者。
完成時,請參閱方案總管視窗並重新整理檢視。
請注意,ASPNETDB。已建立 MDF。 此檔案包含資料表,以支援核心 ASP.NET 服務,例如成員資格。
現在我們可以開始實作結帳程式。
從建立 CheckOut.aspx 頁面開始。
CheckOut.aspx 頁面只能供登入的使用者使用,因此我們將限制登入的使用者存取權,並將未登入的使用者重新導向至 LogIn 頁面。
若要這樣做,我們會將下列內容新增至web.config檔案的組態區段。
<location path="Checkout.aspx">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
ASP.NET Web Forms應用程式的範本會自動將驗證區段新增至我們的web.config檔案,並建立預設登入頁面。
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
我們必須修改 Login.aspx 程式碼後置檔案,以在使用者登入時移轉匿名購物車。 變更Page_Load事件,如下所示。
using System.Web.Security;
protected void Page_Load(object sender, EventArgs e)
{
// If the user is not submitting their credentials
// save refferer
if (!Page.IsPostBack)
{
if (Page.Request.UrlReferrer != null)
{
Session["LoginReferrer"] = Page.Request.UrlReferrer.ToString();
}
}
// User is logged in so log them out.
if (User.Identity.IsAuthenticated)
{
FormsAuthentication.SignOut();
Response.Redirect("~/");
}
}
然後新增類似這樣的 「LoggedIn」 事件處理常式,以將會話名稱設定為新登入的使用者,並在 MyShoppingCart 類別中呼叫 MigrateCart 方法,將購物車中的暫存會話識別碼變更為該使用者。 (在 .cs 檔案中實作)
protected void LoginUser_LoggedIn(object sender, EventArgs e)
{
MyShoppingCart usersShoppingCart = new MyShoppingCart();
String cartId = usersShoppingCart.GetShoppingCartId();
usersShoppingCart.MigrateCart(cartId, LoginUser.UserName);
if(Session["LoginReferrer"] != null)
{
Response.Redirect(Session["LoginReferrer"].ToString());
}
Session["UserName"] = LoginUser.UserName;
}
實作 MigrateCart () 方法,如下所示。
//--------------------------------------------------------------------------------------+
public void MigrateCart(String oldCartId, String UserName)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var myShoppingCart = from cart in db.ShoppingCarts
where cart.CartID == oldCartId
select cart;
foreach (ShoppingCart item in myShoppingCart)
{
item.CartID = UserName;
}
db.SaveChanges();
Session[CartId] = UserName;
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Migrate Shopping Cart - " +
exp.Message.ToString(), exp);
}
}
}
在 checkout.aspx 中,我們會在簽出頁面中使用 EntityDataSource 和 GridView,就像我們在購物車頁面中所做的一樣。
<div id="CheckOutHeader" runat="server" class="ContentHead">
Review and Submit Your Order
</div>
<span id="Message" runat="server"><br />
<asp:Label ID="LabelCartHeader" runat="server"
Text="Please check all the information below to be sure it's correct.">
</asp:Label>
</span><br />
<asp:GridView ID="MyList" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID,UnitCost,Quantity"
DataSourceID="EDS_Cart"
CellPadding="4" GridLines="Vertical" CssClass="CartListItem"
onrowdatabound="MyList_RowDataBound" ShowFooter="True">
<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>
<br />
<asp:imagebutton id="CheckoutBtn" runat="server" ImageURL="Styles/Images/submit.gif"
onclick="CheckoutBtn_Click">
</asp:imagebutton>
<asp:EntityDataSource ID="EDS_Cart" runat="server"
ConnectionString="name=CommerceEntities"
DefaultContainerName="CommerceEntities"
EnableFlattening="False"
EnableUpdate="True"
EntitySetName="ViewCarts"
AutoGenerateWhereClause="True"
EntityTypeFilter=""
Select="" Where="">
<WhereParameters>
<asp:SessionParameter Name="CartID" DefaultValue="0"
SessionField="TailSpinSpyWorks_CartID" />
</WhereParameters>
</asp:EntityDataSource>
請注意,GridView 控制項會指定名為 MyList_RowDataBound 的 「ondatabound」 事件處理常式,讓我們實作類似這樣的事件處理常式。
decimal _CartTotal = 0;
//--------------------------------------------------------------------------------------+
protected void MyList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
TailspinSpyworks.Data_Access.ViewCart myCart = new Data_Access.ViewCart();
myCart = (TailspinSpyworks.Data_Access.ViewCart)e.Row.DataItem;
_CartTotal += myCart.UnitCost * myCart.Quantity;
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
if (_CartTotal > 0)
{
CheckOutHeader.InnerText = "Review and Submit Your Order";
LabelCartHeader.Text = "Please check all the information below to be sure
it's correct.";
CheckoutBtn.Visible = true;
e.Row.Cells[5].Text = "Total: " + _CartTotal.ToString("C");
}
}
}
此方法會保留購物車的執行總計,因為每個資料列都會系結並更新 GridView 的底部資料列。
在此階段,我們已實作要放置之訂單的「檢閱」簡報。
讓我們藉由將幾行程式碼新增至我們的Page_Load事件來處理空的購物車案例:
protected void Page_Load(object sender, EventArgs e)
{
CheckOutHeader.InnerText = "Your Shopping Cart is Empty";
LabelCartHeader.Text = "";
CheckoutBtn.Visible = false;
}
當使用者按一下 [提交] 按鈕時,我們會在 [提交按鈕按一下事件處理常式] 中執行下列程式碼。
protected void CheckoutBtn_Click(object sender, ImageClickEventArgs e)
{
MyShoppingCart usersShoppingCart = new MyShoppingCart();
if (usersShoppingCart.SubmitOrder(User.Identity.Name) == true)
{
CheckOutHeader.InnerText = "Thank You - Your Order is Complete.";
Message.Visible = false;
CheckoutBtn.Visible = false;
}
else
{
CheckOutHeader.InnerText = "Order Submission Failed - Please try again. ";
}
}
訂單提交程式的「主力」是在 MyShoppingCart 類別的 SubmitOrder () 方法中實作。
SubmitOrder 將會:
- 取得購物車中的所有明細專案,並使用這些專案來建立新的訂單記錄和相關聯的 OrderDetails 記錄。
- 計算出貨日期。
- 清除購物車。
//--------------------------------------------------------------------------------------+
public bool SubmitOrder(string UserName)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
//------------------------------------------------------------------------+
// Add New Order Record |
//------------------------------------------------------------------------+
Order newOrder = new Order();
newOrder.CustomerName = UserName;
newOrder.OrderDate = DateTime.Now;
newOrder.ShipDate = CalculateShipDate();
db.Orders.AddObject(newOrder);
db.SaveChanges();
//------------------------------------------------------------------------+
// Create a new OderDetail Record for each item in the Shopping Cart |
//------------------------------------------------------------------------+
String cartId = GetShoppingCartId();
var myCart = (from c in db.ViewCarts where c.CartID == cartId select c);
foreach (ViewCart item in myCart)
{
int i = 0;
if (i < 1)
{
OrderDetail od = new OrderDetail();
od.OrderID = newOrder.OrderID;
od.ProductID = item.ProductID;
od.Quantity = item.Quantity;
od.UnitCost = item.UnitCost;
db.OrderDetails.AddObject(od);
i++;
}
var myItem = (from c in db.ShoppingCarts where c.CartID == item.CartID &&
c.ProductID == item.ProductID select c).FirstOrDefault();
if (myItem != null)
{
db.DeleteObject(myItem);
}
}
db.SaveChanges();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Submit Order - " + exp.Message.ToString(),
exp);
}
}
return(true);
}
針對此範例應用程式的目的,我們只要將兩天新增至目前日期,即可計算出出貨日期。
//--------------------------------------------------------------------------------------+
DateTime CalculateShipDate()
{
DateTime shipDate = DateTime.Now.AddDays(2);
return (shipDate);
}
執行應用程式現在可讓我們從頭到尾測試購物程式。