第 6 部分:ASP.NET 成员身份
作者 :Joe Stagner
注意
自本文撰写以来,ASP.NET 成员资格提供程序已被 ASP.NET Identity 取代。 强烈建议更新应用以使用 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 方法将购物车中的临时会话 ID 更改为用户的会话 ID。 在 .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);
}
现在运行应用程序将使我们能够从头到尾测试购物过程。