使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(九)

实在不好意思,好久没有更新了,我不想找些客观原因来解释,只想请大家见谅!现在我们继续我们的项目,客户已经完成了订单的确认,但我们还没有一个地方可以让客户输入他们的收货信息,我们的商品没办法发货,这是个严重的问题,我们必须解决它。现在,我们就在SportsStore.Domain工程的Entities文件夹中添加一个ShippingDetails类,在这个类中,我们使用了System.ComponentModel.DataAnnotations命名空间,去验证客户的输入:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations; namespace SportsStore.Domain.Entities
{
public class ShippingDetails
{
[Required(ErrorMessage = "Please enter a name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter the first address line")]
public string Line1 { get; set; } public string Line2 { get; set; } public string Line3 { get; set; }
[Required(ErrorMessage = "Please enter a city name")]
public string City { get; set; }
[Required(ErrorMessage = "Please enter a state name")]
public string State { get; set; }
public string Zip { get; set; }
[Required(ErrorMessage = "Please enter a country name")]
public string Country { get; set; }
public bool GiftWrap { get; set; }
}
}

我们的目的是让用户输入收货的详细信息后能够去付款,毕竟要赚钱吗,这个没啥不好意思的,我们这就去修改一下我们的summary视图,打开Views/Cart/Index.cshtml文件,我们要在这添加一个支付按钮,修改文件的最后部分像下面的样子,然后,运行一下你的代码,看看效果:)

</table> <p align="center" class="actionButtons">
<a href="@Model.ReturnUrl">继续购物</a>
@Html.ActionLink("支付", "Checkout") </p>

正如你所预见的,现在我们要为CartController类添加一个Checkout Action方法:

public ViewResult Checkout() {
return View(new ShippingDetails());
}

Checkout方法返回一个默认的view,并传递一个new ShippingDetails对象作为view model. 现在我们就去创建一个ShippingDetails类型的强视图:

修改视图代码如下:

@model SportsStore.Domain.Entities.ShippingDetails
@{ ViewBag.Title = "SportStore: Checkout"; }
<h2>现在支付</h2>
请输入你的详细信息, 我们会根据您的信息发货!
@using (Html.BeginForm()) { <h3>发货到</h3>
<div>姓名: @Html.EditorFor(x => x.Name)</div>
<h3>地址</h3>
<div>Line 1: @Html.EditorFor(x => x.Line1)</div>
<div>Line 2: @Html.EditorFor(x => x.Line2)</div>
<div>Line 3: @Html.EditorFor(x => x.Line3)</div>
<div>城市: @Html.EditorFor(x => x.City)</div>
<div>区: @Html.EditorFor(x => x.State)</div>
<div>邮编: @Html.EditorFor(x => x.Zip)</div>
<div>国家: @Html.EditorFor(x => x.Country)</div>
<h3>可选项</h3>
<label>
@Html.EditorFor(x => x.GiftWrap) 作为礼品包装我的商品 </label>
<p align="center">
<input class="actionButtons" type="submit" value="完成订单" /> </p>
}

实现订单处理器

我们需要一个组件,通过这个组件,我们能够容易的把握订单的处理流程,为了保持遵守MVC模型的基本原则,我们要定义一个接口,写一个这个接口的实现类,使我们的DI容器和 Ninject和这个实现类整合在一起. 
添加一个IOrderProcessor接口到SportsStore.Domain工程的Abstract文件夹:

using SportsStore.Domain.Entities;
namespace SportsStore.Domain.Abstract
{
public interface IOrderProcessor
{
void ProcessOrder(Cart cart, ShippingDetails shippingDetails);
}
}

实现接口

IOrderProcessor接口的实现类将通过发送额email给管理员处理订单,当然了,我们简化了这个流程,真正的大型商务网站不只是发邮件这么简单! 现在我们要创建一个新类,叫做 EmailOrderProcessor,把它放在SportsStore.Domain工程的Concrete文件夹中,这个类我们使用.NET Framework library内建的SMTP去发送邮件:

using System.Net.Mail;
using System.Text;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using System.Net; namespace SportsStore.Domain.Concrete {
public class EmailSettings {
public string MailToAddress = "orders@example.com";
public string MailFromAddress = "sportsstore@example.com";
public bool UseSsl = true;
public string Username = "MySmtpUsername";
public string Password = "MySmtpPassword";
public string ServerName = "smtp.example.com";
public int ServerPort = 587;
public bool WriteAsFile = false;
public string FileLocation = @"c:\sports_store_emails";
} public class EmailOrderProcessor :IOrderProcessor { private EmailSettings emailSettings; public EmailOrderProcessor(EmailSettings settings)
{
emailSettings = settings;
} public void ProcessOrder(Cart cart, ShippingDetails shippingInfo)
{ using (var smtpClient = new SmtpClient())
{
smtpClient.EnableSsl = emailSettings.UseSsl;
smtpClient.Host = emailSettings.ServerName;
smtpClient.Port = emailSettings.ServerPort;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential(emailSettings.Username, emailSettings.Password); if (emailSettings.WriteAsFile) {
smtpClient.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
smtpClient.PickupDirectoryLocation = emailSettings.FileLocation;
smtpClient.EnableSsl = false;
}
StringBuilder body = new StringBuilder().AppendLine("A new order has been submitted")
.AppendLine("---").AppendLine("Items:"); foreach (var line in cart.Lines) {
var subtotal = line.Product.Price * line.Quantity;
body.AppendFormat("{0} x {1} (subtotal: {2:c}", line.Quantity, line.Product.Name, subtotal); }
body.AppendFormat("Total order value: {0:c}", cart.ComputeTotalValue()).AppendLine("---")
.AppendLine("Ship to:").AppendLine(shippingInfo.Name).AppendLine(shippingInfo.Line1)
.AppendLine(shippingInfo.Line2 ?? "") .AppendLine(shippingInfo.Line3 ?? "")
.AppendLine(shippingInfo.City).AppendLine(shippingInfo.State ?? "")
.AppendLine(shippingInfo.Country) .AppendLine(shippingInfo.Zip).AppendLine("---")
.AppendFormat("Gift wrap: {0}",shippingInfo.GiftWrap ? "Yes" : "No"); MailMessage mailMessage = new MailMessage(emailSettings.MailFromAddress, // From
emailSettings.MailToAddress, // To
"New order submitted!", // Subject
body.ToString()); // Body if (emailSettings.WriteAsFile)
{
mailMessage.BodyEncoding = Encoding.ASCII;
}
smtpClient.Send(mailMessage);
}
}
}
}

注册实现类

为了让Ninject能够创建 IOrderProcessor接口的实现类,我们必须添加一些代码到SportsStore.WebUI 工程的NinjectControllerFactory 类的AddBindings 方法,到这个方法里添加代码,不用我说你也知道要干什么事了,马上动手吧!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using Moq;
using Ninject;
using SportsStore.Domain.Concrete;
using System.Configuration; namespace SportsStore.WebUI.Infrastructure
{
public class NinjectControllerFactory: DefaultControllerFactory
{ private IKernel ninjectKernel; public NinjectControllerFactory() {
ninjectKernel = new StandardKernel();
AddBindings();
} protected override IController GetControllerInstance(RequestContext
requestContext, Type controllerType) { return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
} private void AddBindings() { Mock<IProductsRepository> mock = new Mock<IProductsRepository>(); //mock.Setup(m => m.Products).Returns(new List<Product> {
// new Product { Name = "Football", Price = 25 },
// new Product { Name = "Surf board", Price = 179 },
// new Product { Name = "Running shoes", Price = 95 }
//}.AsQueryable());
//ninjectKernel.Bind<IProductsRepository>().ToConstant(mock.Object);
ninjectKernel.Bind<IProductsRepository>().To<EFProductRepository>(); EmailSettings emailSettings = new EmailSettings {
WriteAsFile = bool.Parse(ConfigurationManager.AppSettings["Email.WriteAsFile"] ?? "false") };
ninjectKernel.Bind<IOrderProcessor>().To<EmailOrderProcessor>().WithConstructorArgument("settings", emailSettings);
}
}
}

我们创建了一个EmailSettings 对象, 当一个服务请求要求创建一个新的IOrderProcessor 接口实力的时候,我们使用Ninject的WithConstructorArgument 方法注入它到EmailOrderProcessor构造函数,因为我们使用了ConfigurationManager.AppSettings 属性去访问 Web.config文件,所以,我们要将一些配置添加到Web.config 文件中:

<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="Email.WriteAsFile" value="true"/>
</appSettings>

完善Cart Controller 
我们要修改CartController类,让它的构造函数去要求一个IOrderProcessor接口的实现,并添加一个新的方法处理用户点击完成订单按钮时,post过来的Http请求:

        private IOrderProcessor orderProcessor;

        public CartController(IProductsRepository repo, IOrderProcessor proc)
{
repository = repo; orderProcessor = proc;
}
        [HttpPost]
public ViewResult Checkout(Cart cart, ShippingDetails shippingDetails)
{
if (cart.Lines.Count() == 0)
{
ModelState.AddModelError("", "Sorry, your cart is empty!");
} if (ModelState.IsValid) {
orderProcessor.ProcessOrder(cart, shippingDetails);
cart.Clear(); return View("Completed");
}
else
{
return View(shippingDetails);
}
}

你现在看到了,我们添加的Checkout方法带有一个HttpPost 属性,这意味着它将为一个post请求调用,当用户提交一个表单时,我们将依赖MVC的model binder system, ShippingDetails 参数和Cart 参数创建我们的model binder。

为了展示用户的输入错误,我们需要在Checkout view中添加 @Html.ValidationSummary() 标记,看起来应该像下面的样子:

<h2>现在支付</h2>
请输入你的详细信息, 我们会根据您的信息发货!
@using (Html.BeginForm()) {
@Html.ValidationSummary()
<h3>发货到</h3>

……

展示Summary页
为了完善支付流程, 我们应该显示一个订单已经被处理的确认页给用户,右击CartController类的任意方法去添加一个视图,命名为Completed,这个视图我们不需要定义为强类型:

@{     ViewBag.Title = "SportsStore: Order Submitted"; }
<h2>谢谢!</h2>
感谢您购买我们的商品. 我们将尽可能快的发送货物给您.

运行你的程序前,别忘了修改你的email账户和密码,还有C盘下要建一个c:\sports_store_emails文件夹哦!在下一篇中,我们将为我们的网站创建一个CRUD的管理后台,这是所有网站都比不可少的功能,我们当然也不会少了!感谢您的关注!如果有任何问题请在我的博客上留言,我会尽可能详尽的为您解答,下篇再见!

王志岳 塔塔信息技术(中国)股份有限公司 | 开发者导航

SQL Server 性能优化之——T-SQL NOT IN 和 NOT Exists

这次介绍一下T-SQL中“Not IN” 和“Not Exists”的优化。

Not IN  Not Exists 命令 :

有些情况下,需要select/update/delete 操作孤立数据。孤立数据:不存在主表中而存在其关联表中。

操作这样的数据,一般第一反应是利用“Not in” 或 “Not Exists”命令。使用Not IN会严重影响性能,因为这个命令会逐一检查每个记录,就会造成资源紧张,尤其是当对大数据进行更新和删除操作时,可能导致资源被这些操作锁住。

.

选择NOT IN 还是 NOT Exists

现在SQL Server 中有两个命令可以使用大数据的插入、更新、删除操作,不仅性能方面比NOT IN 和 NOT Exists有很大的提高,而且语法简单,写出来的语句看上去也很清爽。 现在就请它们闪亮登场,Merge 和 Except。

例子:

首先创建两个表

   1:  use [MyTest]
   2:  Create table Test1 (name varchar (100) )
   3:  Create table Test2 (name varchar (100) )

使用Not IN命令Select/update/delete操作:

   1:  SELECT name FROM Test1 where name not in (select name from Test2)
   2:  UPDATE Test1 SET name =N'New_Name' where name not in (select name from Test2)
   3:  DELETE Test1 FROM Test1 where name not in (select name from Test2)

使用性能更好的Merge and Except

   1:  merge Test1 T using (select name from Test1 except select name from Test2 )S on t.name=s.name
   2:  when matched then update SET name=N'New_Name' ;
   3:  merge Test1 T using (select name from Test1 except select name from Test2 )S on t.name=s.name
   4:  when matched then delete ;
   5:  SELECT * FROM Test1 S where not exists (select 1 from Test1 inner join Test2 on Test1.name=Test2.name and Test1.name=s.name)
 

注意,上面还是有一部分使用了Not Exists:

   1:  SELECT * FROM Test1 S where not exists (select 1 from Test1 inner join Test2 on Test1.name=Test2.name and Test1.name=s.name)

现在需要使用高效的Except:

   1:  select name from Test1 except select name from Test2

在这里只是给出了例子,没有拿出实际的对比数据。但是Merge 和Except 两个命令在大数据的处理方面的性能,要比

Not IN 和Not EXISTS 好很多。不管你信不信,反正我信了!!!

敬请期待测试数据

在此谢谢读完这篇博客,有什么写的不对的地方请指正

有帮助就推荐下,有感想就下下来,不满意就留言,有问题就更正。

 
 
分类: SQL
标签: 数据库

构建一个真实的应用电子商务SportsStore9的更多相关文章

  1. 使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore

    05 2013 档案 使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(一) 摘要: 完成SportsStore电子商务平台,你将学会: 1.使用MVC4开 ...

  2. 构建一个真实的应用电子商务SportsStore(十)

    构建一个真实的应用电子商务SportsStore(十) 我们现在还需要为管理员提供一个途径,使他能方便的管理网站的商品目录,这也是所有网站都需要的功能,常用到了几乎所有开发人员都要开发这种功能的地步, ...

  3. 构建一个真实的应用电子商务SportsStore(十一)

    构建一个真实的应用电子商务SportsStore(十一) 我们的项目已经进入了非常好的良性循环,项目中涵盖了多数现在的主流开源框架的使用.就Ninject而言,我们的运用是非常的成功,没有任何一点多余 ...

  4. 构建具有用户身份认证的 React + Flux 应用程序

    原文:Build a React + Flux App with User Authentication 译者:nzbin 译者的话:这是一篇内容详实的 React + Flux 教程,文章主要介绍了 ...

  5. Angular2 入门

    1. 说明 该文档为Angular2的入门文档,可以根据该文档的内如做出一个“helloworld”类型的Angualr2入门程序,通过该文档可以初步了解Angular2的相关知识以及开发流程,同时搭 ...

  6. MYSQL数据库自动本地/异地双备份/MYSQL增量备份

    构建高安全电子商务网站之(网站文件及数据库自动本地/异地双备份)架构图 继续介绍Linux服务器文件备份,数据库备份,数据安全存储相关的电子商务系统架构.针对安全性有多种多样的解决方案,其中数据备份是 ...

  7. EasyMock 使用方法与原理剖析

    from:http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/ Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一 ...

  8. 业界最具影响力MySQL精品文章荟萃(300篇)

    MySQL是一种关联数据库管理系统,SQL语言是用于访问数据库的最常用标准化语言.本文档收集的资料有MySQL数据库备份与恢复,配置,解决方案等,供大家方便统一阅读. 博客专题 1     MySQL ...

  9. EasyMock 使用方法与原理剖析--转载

    原文地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/ Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一 ...

随机推荐

  1. sql server 视图 的一个例子

    这是一个 有点复杂的查询.我现在 想把他封装 成 视图  其中  B.RecordID= 41 提供给 视图外查询. create view view_UserRecord as select Rec ...

  2. HDU 1501 Zipper(DP,DFS)

    意甲冠军  是否可以由串来推断a,b字符不改变其相对为了获取字符串的组合c 本题有两种解法  DP或者DFS 考虑DP  令d[i][j]表示是否能有a的前i个字符和b的前j个字符组合得到c的前i+j ...

  3. hdu 5053 the Sum of Cube(上海网络赛)

    the Sum of Cube Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. c# 自定义数据类型

    定义引用类型用 class  ,值类型 用 struct ,涉及数据转换就用 上一篇的方法做 ,涉及 泛型就用 in  关键字 不用 in interface IContravariant<A& ...

  5. Cocos2d-x 3.0 编译出错 解决 error: expected &#39;;&#39; at end of member declaration

    近期把项目移植到cocos2d-x 3.0,在整Android编译环境的时候,出现一大堆的编译出错,都是类似"error: expected ';' at end of member dec ...

  6. ASP.NET Web Service中使用Session 及 Session丢失解决方法 续

    原文:ASP.NET Web Service中使用Session 及 Session丢失解决方法 续 1.关于Session丢失问题的说明汇总,参考这里 2.在Web Servcie中使用Sessio ...

  7. springMVC 获取本地项目路径 及后整理上传文件的方法

    String path=request.getSession().getServletContext().getRealPath("upload/img/product"); // ...

  8. MonkeyRunner源码分析之-谁动了我的截图?

    本文章的目的是通过分析monkeyrunner是如何实现截屏来作为一个例子尝试投石问路为下一篇文章做准备,往下一篇文章本人有意分析下monkeyrunner究竟是如何和目标测试机器通信的,所以最好的办 ...

  9. oracle存储过程+游标处理select数据

    create or replace PROCEDURE UPDATE_RECORDCODE is cursor location_data is select * from location wher ...

  10. [译]Java 设计模式之备忘录

    (文章翻译来自Java Design Pattern: Memento) memento是一个保存另外一个对象内部状态拷贝的对象.这样以后就可以将该对象恢复到原先保存的状态. 在将来时空旅行将成为显示 ...