ASP.NET MVC SportStore 购物网示例(5)
创建一个自定义的Model绑定
在WebUI根目录添加 CartModelBinder类
public class CartModelBinder : IModelBinder
{
private const string cartSessionKey = "_cart";
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
throw new InvalidOperationException("Cannot update instances");
// reurn the cart form session[](create it first if necessary)
Cart cart = (Cart)controllerContext.HttpContext.Session[cartSessionKey];
if (cart == null)
{
cart = new Cart();
controllerContext.HttpContext.Session[cartSessionKey] = cart;
}
return cart;
}
}
通知MVC使用:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());
ModelBinders.Binders.Add(typeof(Cart), new CartModelBinder());
}
创建 CartController
创建CartController的单元测试
[TestFixture]
public class CartControllerTest
{
[Test]
public void Can_Add_Product_To_Cart()
{
var mockProductsRepos = new Moq.Mock<IProductsRepository>();
var products = new List<Product>
{
new Product{ProductID = 14,Name="Much Ado About Nothig"},
new Product{ProductID = 27,Name="The Comedy of error"}
};
mockProductsRepos.Setup(x => x.Products).Returns(products.AsQueryable());
var cart = new Cart();
var controller = new CartController(mockProductsRepos.Object);
RedirectToRouteResult result =
controller.AddToCart(cart, 27, "someReturnUrl");
Assert.AreEqual(1, cart.Lines.Count);
Assert.AreEqual("The comedy of Errors", cart.Lines[0].Product.Name);
Assert.AreEqual(1, cart.Lines[0].Quantity);
// Check that the visitor was redirected to the cart display screen
Assert.AreEqual("Index", result.RouteValues["action"]);
Assert.AreEqual("someReturnUrl", result.RouteValues["returnUrl"]);
}
}
F5运行测试。单击 Add to Cart 按钮。
测试CartController的Index Action
[Test]
public void Index_Action_Renders_Default_View_Width_Cart_and_ReturnUrl()
{
// Set up the controller
Cart cart = new Cart();
CartController controller = new CartController(null);
// Invoke action method
ViewResult result = controller.Index(cart, "myReturnUrl");
// Verify results
Assert.IsEmpty(result.ViewName); // Renders default view
Assert.AreSame(cart, result.ViewData.Model);
Assert.AreEqual("myReturnUrl", result.ViewData["returnUrl"]);
Assert.AreEqual("Cart", result.ViewData["CurrentCategory"]);
}
为Index添加 View
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<DomainModel.Entities.Cart>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
SportsStore : Your Cart
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Your cart</h2>
<table width="90%" align="center">
<thead>
<tr>
<th align="center">
Quantity
</th>
<th align="left">
Item
</th>
<th align="right">
Price
</th>
<th align="right">
Subtotal
</th>
</tr>
</thead>
<tbody>
<% foreach (var line in Model.Lines)
{%>
<tr>
<td align="center">
<%= line.Quantity %>
</td>
<td align="left">
<%= line.Product.Name %>
</td>
<td align="right">
<%= line.Product.Price.ToString("c") %>
</td>
<td align="right">
<%= (line.Quantity*line.Product.Price).ToString("c") %>
</td>
</tr>
<% } %>
</tbody>
<tfoot>
<tr>
<td colspan="3" align="right">
Total:
</td>
<td align="right">
<%= Model.ComputeTotalValue().ToString("c") %>
</td>
</tr>
</tfoot>
</table>
<p align="center" class="actionButtons">
<a href="<%= Html.Encode(ViewData["returnUrl"]) %>">Continue shopping</a>
</p>
</asp:Content>
添加样式:
H2 { margin-top: 0.3em } ; font-weight: bold; }
TFOOT TD { border-top: 1px dotted gray
.actionButtons A {
font: .8em Arial; color: White; margin: 0 .5em 0 .5em;
text-decoration: none; padding: .15em 1.5em .2em 1.5em;
background-color: #353535; border: 1px solid black;
}
F5测试运行。
从购物车中移除商品
为Cart/Index.aspx添加 移除 按钮。
<% foreach (var line in Model.Lines)
{%>
<tr>
<td align="center">
<%= line.Quantity %>
</td>
<td align="left">
<%= line.Product.Name %>
</td>
<td align="right">
<%= line.Product.Price.ToString("c") %>
</td>
<td align="right">
<%= (line.Quantity*line.Product.Price).ToString("c") %>
</td>
<td>
<% using (Html.BeginForm("RemoveFromCart", "Cart"))
{ %>
<%= Html.Hidden("ProductID", line.Product.ProductID) %>
<%= Html.Hidden("returnUrl", ViewData["returnUrl"]) %>
<input type="submit" value="Remove" />
<% } %>
</td>
</tr>
<% } %>
Displaying a Cart Summary in the Title Bar
为CartController添加如下方法:
public ViewResult Summary(Cart cart)
{
return View(cart);
}
为Summary创建View
代码如下:
<% if (Model.Lines.Count > 0)
{ %>
<div id="cart">
<span class="caption"><b>Your cart:</b>
<%= Model.Lines.Sum(x => x.Quantity) %>
item(s),
<%= Model.ComputeTotalValue().ToString("c") %>
</span>
<%= Html.ActionLink("Check out", "Index", "Cart",
new { returnUrl = Request.Url.PathAndQuery }, null)%>
</div>
<% } %>
修改Site.master
<div id="header">
<% if (!(ViewContext.Controller is WebUI.Controllers.CartController))
Html.RenderAction("Summary", "Cart"); %>
<div class="title">
体育用品商场</div>
</div>
添加样式:
DIV#cart { float:right; margin: .8em; color: Silver;
background-color: #555; padding: .5em .5em .5em 1em; }
DIV#cart A { text-decoration: none; padding: .4em 1em .4em 1em; line-height:2.1em;
margin-left: .5em; background-color: #333; color:White; border: 1px solid black;}
DIV#cart SPAN.summary { color: White; }
F5 测试运行。
提交结果
创建ShippingDetails领域模型
public class ShippingDetails : IDataErrorInfo
{
public string Name { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
public bool GiftWrap { get; set; }
public string this[string columnName] // Validation rules
{
get
{
if ((columnName == "Name") && string.IsNullOrEmpty(Name))
return "Please enter a name";
if ((columnName == "Line1") && string.IsNullOrEmpty(Line1))
return "Please enter the first address line";
if ((columnName == "City") && string.IsNullOrEmpty(City))
return "Please enter a city name";
if ((columnName == "State") && string.IsNullOrEmpty(State))
return "Please enter a state name";
if ((columnName == "Country") && string.IsNullOrEmpty(Country))
return "Please enter a country name";
return null;
}
}
public string Error { get { return null; } } // Not required
}
在CartTest中测试Shipping Details类
[Test]
public void Cart_Shipping_Details_Start_Empty()
{
Cart cart = new Cart();
ShippingDetails d = cart.ShippingDetails;
Assert.IsNull(d.Name);
Assert.IsNull(d.Line1); Assert.IsNull(d.Line2); Assert.IsNull(d.Line3);
Assert.IsNull(d.City); Assert.IsNull(d.State); Assert.IsNull(d.Country);
Assert.IsNull(d.Zip);
}
[Test]
public void Cart_Not_GiftWrapped_By_Default()
{
Cart cart = new Cart();
Assert.IsFalse(cart.ShippingDetails.GiftWrap);
}
编译错误,在实体Cart类中添加如下代码 :
private ShippingDetails shippingDetails = new ShippingDetails();
public ShippingDetails ShippingDetails { get { return shippingDetails; } }
添加
Check Out Now 按钮
在Vew/Cart/Index.aspx中添加
<%= Html.ActionLink("Check out now", "CheckOut") %>
查看客户的详细购物资料
在CartController中添加CheckOut Action:
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult CheckOut(Cart cart)
{
return View(cart.ShippingDetails);
}
为CheckOut创建View。
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Check out now</h2>
Please enter your details, and we'll ship your goods right away!
<% using (Html.BeginForm())
{ %>
<h3>
Ship to</h3>
<div>
Name:
<%= Html.TextBox("Name") %></div>
<h3>
Address</h3>
<div>
Line 1:
<%= Html.TextBox("Line1") %></div>
<div>
Line 2:
<%= Html.TextBox("Line2") %></div>
<div>
Line 3:
<%= Html.TextBox("Line3") %></div>
<div>
City:
<%= Html.TextBox("City") %></div>
<div>
State:
<%= Html.TextBox("State") %></div>
<div>
Zip:
<%= Html.TextBox("Zip") %></div>
<div>
Country:
<%= Html.TextBox("Country") %></div>
<h3>
Options</h3>
<%= Html.CheckBox("GiftWrap") %>
Gift wrap these items
<p align="center">
<input type="submit" value="Complete order" /></p>
<% } %>
</asp:Content>
F5 运行测试
转载请注明出处! Author: im@xingquan.org