第十话 Asp.Net MVC 3.0 【MVC项目实战の六】

今天主要演示的就是前面项目的后台功能的开发,在后台我们搞了一个上传图片的功能,具体的下面开始!(这次东东可能有点多,想学习的同学可要耐心的看哦!)

考虑到是我们需要搞一个图片上传的功能,所以我们的表肯定也添加新的字段等;还有我们后台要有区别于前台的模版等!接下来就一步一步的完善吧!

首先添加管理目录,我们习惯用下面的页面来管理我们的数据,如下图1.

图1.这是一个CRUD的草图(CRUD:它代表创建(Create)、更新(Update)、读取(Read)和删除(Delete)操作,这里是简称)。

接下来创建一个CURD的Controller(控制器),在我们的Web项目的Controllers文件夹下创建,如下图2.

图2.命名为"AdminController",具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;

namespace SportsStore.WebUI.Controllers
{
    [Authorize]
    public class AdminController : Controller
    {
        private IProductRepository repository;
        public AdminController(IProductRepository repo)
        {
            this.repository = repo;
        }
        /// <summary>
        /// 展示商品列表页面
        /// </summary>
        /// <returns>商品的列表</returns>
        public ViewResult Index()
        {
            return this.View(this.repository.Products);
        }
    }
}

这里我们写了一个很简单的Index Action(方法),现在先开始弄一个简单的后台页面出来,我们创建一个相应的视图!哦,忘了。我们后台又有却别于前台的模版页面,所以我们新建一个模版页面如下图3.

图3.(在们web项目的Views/Shared文件夹下创建),创建好我们对模版修改如下:

<!DOCTYPE html>

<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Admin.css")" rel="Stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
</head>
<body>
    <div>
    @if (TempData["message"]!=null)
    {
        <div class="Message">@TempData["Message"]</div>
    }
        @RenderBody()
    </div>
</body>
</html>

蓝色加粗部分是我们的后台样式,具体代码如下;红色加粗部分引入的JS是为了验证客户端数据;粉红色加粗部分则是一个提示信息的预留位置。

后台样式我们在web项目的Content文件下创建,具体样式如下:

BODY, TD { font-family: Segoe UI, Verdana }
H1 { padding: .5em; padding-top: 0; font-weight: bold; 
     font-size: 1.5em; border-bottom: 2px solid gray; }
DIV#content { padding: .9em; }
TABLE.Grid TD, TABLE.Grid TH { border-bottom: 1px dotted gray; text-align:left; }
TABLE.Grid { border-collapse: collapse; width:100%; } 
TABLE.Grid TH.NumericCol, Table.Grid TD.NumericCol {
    text-align: right; padding-right: 1em; }
FORM {margin-bottom: 0px;   } 
DIV.Message { background: gray; color:White; padding: .2em; margin-top:.25em; } 

.field-validation-error { color: red; display: block; }
.field-validation-valid { display: none; }
.input-validation-error { border: 1px solid red; background-color: #ffeeee; }
.validation-summary-errors { font-weight: bold; color: red; }
.validation-summary-valid { display: none; }

.editor-field { margin-bottom: .8em; }
.editor-label { font-weight: bold; }
.editor-label:after { content: ":" }
.text-box { width: 25em; }
.multi-line { height: 5em; font-family: Segoe UI, Verdana; }

OK!现在回到我们的AdminController里面来,创建我们的List展示页面,具体如下图4.

图4.建立好Index.cshtml页面,修改它的代码如下:

@model IEnumerable<SportsStore.Domain.Entities.Product>

@{
    ViewBag.Title = "Administration All Index";
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}

<h1>Administration All Index</h1>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="Grid">
    <tr>
        <th>ID</th> 
        <th>Name</th>  
        <th class="NumericCol">Price</th> 
        <th>Actions</th> 
    </tr>
    @foreach (var item in Model)
    {
    <tr>
        <td>@item.ProductID</td>
        <td>@Html.ActionLink(item.Name, "Edit", new { item.ProductID })</td> 
        <td class="NumericCol">@item.Price.ToString("c")</td> 
        <td>
        @using (Html.BeginForm("Delete", "Admin"))
        {
          @Html.Hidden("ProductID", item.ProductID)  
            <input type="submit" value="Delete"/>
        }
        </td> 
    </tr>
    }
</table>
<p>@Html.ActionLink("Add a New Product","Create")</p>

写完这个我们运行一下我们的项目,结果如下图5.(因为这个跟前台没有直接关联,所以写完需要我们拼写它的路径也就是你想看页面的Controller/Index的URL方式)。

图5.这个后台一个简单的展示页面,他现在只具备列出我们所有商品,像新建,编辑,删除的功能还不存在。接下来一并搞这个三个功能,都是在我们的AdminController控制器里完成,首先来看编辑和新建功能。

一个编辑功能应该是管理者可以修改商品的属性(信息)等,接下来我们在AdminController添加一个编辑功能,具体代码如下:

        /// <summary>
        /// 编辑方法
        /// </summary>
        /// <param name="productId">商品的ID</param>
        /// <returns>编辑后的商品</returns>
        public ViewResult Edit(int productId)
        {
            Product product = this.repository.Products.FirstOrDefault(h => h.ProductID == productId);
            return this.View(product);
        }

接着我们创建Edit Action(方法)对应的视图页面,具体如下图6(我们在这里还继续使用强类型数据模型).

图6.创建完Edit.cshtml后,我们修改他如下:

@model SportsStore.Domain.Entities.Product

@{
    ViewBag.Title = "Admin:Edit" + @Model.Name;
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h1>Admin Edit @Model.Name</h1>
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" value="Save" />
    @Html.ActionLink("Cancel And Return To List", "Index")
}

上面红色加粗部分@Html.EditorForModel()是一个复制方法,MVC框架会自动检测创建编辑窗口,运行可以看到效果如下图7.

图7.我们一般习惯在编辑的时候,不让编辑ProductID这个属性,还有我们的描述相比其他的字体应该更小点。我们可以在这里试着用一下"模型元数据"(model metadata)这个后面在做讲解,修改我们Product的实体类如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace SportsStore.Domain.Entities
{
    public class Product : Object
    {
        [HiddenInput(DisplayValue = false)]
        public int ProductID { get; set; }

        public string Name { get; set; }

        [DataType(DataType.MultilineText)]
        public string Description { get; set; }

        public decimal Price { get; set; }

        public string Category { get; set; }
    }
}

 在MVC框架里HiddenInput会是呈现的属性隐藏起来,DataType给定我们一个值允许我们执行相应的编辑。添加玩属性后在运行我们的项目如下图8.

图8.我们之前编辑的商品信息,怎么保存到储存卡呢!我们需要在IProductRepository接口添加保存的方法,这是在需要保存的地方调用方法即可;所以我们修改IProductRepository接口如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Domain.Entities;

namespace SportsStore.Domain.Abstract
{
    public interface IProductRepository
    {
        IQueryable<Product> Products { get; }

        //保存商品
        void SaveProduct(Product product);
    }
}

接着我们需要在EFProductRepository类里实现他,具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Domain.Abstract;
using System.Data.Entity;
using SportsStore.Domain.Entities;

namespace SportsStore.Domain.Concrete
{
    public class EFProductRepository : IProductRepository
    {

        private EFDbContext context = new EFDbContext();
        public IQueryable<Product> Products
        {
            get { return this.context.Products; }
        }
        //实现接口里保存商品的方法
        public void SaveProduct(Product product) 
        {
            //不存在商品就新增
            if (product.ProductID == 0)
            {
                this.context.Products.Add(product);
            }
            this.context.SaveChanges();
        }

    }

    //EFDbContext类可以使简单数据模型与数据库交互
    public class EFDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
    }
}

接下来我们实现Edit Action(方法)的Post提交处理,具体代码如下:

        [HttpPost]
        public ActionResult Edit(Product product)
        {
            if (ModelState.IsValid)
            {
                this.repository.SaveProduct(product);
                //设置临时字典
                TempData["message"] = string.Format("{0} Has Been Saved", product.Name);
                return this.View(product);
                    //.RedirectToAction("Index");
           }
        } 

我们检查模型绑定器已经能够验证用户提交的数据。如果一切OK,我们就可以保存到储存库里面。

然后我们更新一下一条信息看看效果,运行如下图9.

图9.因为在这里我们建立的模版里留着提示消息的位置,使用TempData来显示消息,TempData会自动获取传递的字典数据,而且他会自动销毁数据,我们只要从新刷新页面他就会销毁当前传递的数据。

接下来我们需要添加模型验证,就目前而言,我们编辑的时候,价格可以输入负值,商品描述为空等都可以保存,而这些是不允许,所以我们需要给我们的商品模型添加验证属性,具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;

namespace SportsStore.Domain.Entities
{
    public class Product : Object
    {
        [HiddenInput(DisplayValue = false)]
        public int ProductID { get; set; }

        [Required(ErrorMessage = "Please enter a product name")]
        public string Name { get; set; }

        [Required(ErrorMessage = "Please enter a description")]
        [DataType(DataType.MultilineText)]
        public string Description { get; set; }

        [Required]
        [Range(0.01, double.MaxValue, ErrorMessage = "Please enter a positive price")]
        public decimal Price { get; set; }

        [Required(ErrorMessage = "Please specify a category")]
        public string Category { get; set; }

        public byte[] ImageData { get; set; }

        [HiddenInput(DisplayValue = false)]
        public string ImageMimeType { get; set; }
    }
}

添加验证特性后,我们运行项目如果输入错误的话,会有相应的提示,如下图10.

图10.

然后我们实现新建商品功能,在AdminController里添加Create Action(方法),具体代码如下:

        /// <summary>
        /// 创建商品
        /// </summary>
        /// <returns>新的商品</returns>
        public ViewResult Create()
        {
            return this.View("Edit", new Product());
        }

我们这里没有返回默认视图,而是指定到Edit Action(方法),我们试着显示指定在别的Controller控制器和Action方法来搞搞。修改我们的编辑(Edit.cshtml)页面如下:

@model SportsStore.Domain.Entities.Product

@{
    ViewBag.Title = "Admin:Edit" + @Model.Name;
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h1>Admin Edit @Model.Name</h1>
@using (Html.BeginForm("Edit", "Admin"))
{
    @Html.EditorForModel()
    <input type="submit" value="Save" />
    @Html.ActionLink("Cancel And Return To List", "Index")
}

试着运行我们的项目如下图10。

图10我们新建的商品信息,然后接续我们的删除操作。和保存一样我们在IProductRepository接口里定义删除的方法如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Domain.Entities;

namespace SportsStore.Domain.Abstract
{
    public interface IProductRepository
    {
        IQueryable<Product> Products { get; }

        //保存商品
        void SaveProduct(Product product);

        //删除商品
        void DeleteProduct(Product product);
    }
}

接着我们在EFProductRepository类里实现上面定义的删除方法,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Domain.Abstract;
using System.Data.Entity;
using SportsStore.Domain.Entities;

namespace SportsStore.Domain.Concrete
{
    public class EFProductRepository : IProductRepository
    {

        private EFDbContext context = new EFDbContext();
        public IQueryable<Product> Products
        {
            get { return this.context.Products; }
        }
        //实现接口里保存商品的方法
        public void SaveProduct(Product product) 
        {
            //不存在商品就新增
            if (product.ProductID == 0)
            {
                this.context.Products.Add(product);
            }
            this.context.SaveChanges();
        }
        //实现接口的删除商品的方法
        public void DeleteProduct(Product product) 
        {
            this.context.Products.Remove(product);
            this.context.SaveChanges();
        }
    }

    //EFDbContext类可以使简单数据模型与数据库交互
    public class EFDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
    }
}

然后继续在AdminController里添加我们的删除功能,具体代码如下:

        /// <summary>
        /// 删除商品
        /// </summary>
        /// <param name="productID">商品的ID</param>
        /// <returns>URL从新指向列表</returns>
        [HttpPost]
        public ActionResult Delete(int productId)
        {
            Product prod = this.repository.Products.FirstOrDefault(h => h.ProductID == productId);
            if (prod!=null)
            {
                this.repository.DeleteProduct(prod);
                TempData["message"] = string.Format("{0} Was Deleted", prod.Name);
            }
            return this.RedirectToAction("Index");
        }

搞完删除运行一下我们的项目,试试删除功能,具体如下图11.

图11.(删除了ID为15的信息)我们的后台应该有一个简单的登录页面,做也要做个样子吗?简单的搞搞我们只要说明那么回事。Asp.Net MVC是建立在Asp.Net核心平台上的,所以我们可以访问Asp.Net Form验证的功能,这也是一个比较通用的功能。只有登录成功的人才能操作后台。关于From验证我们配置我们项目的Web.Config如下:

......
 <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880">
        <credentials passwordFormat="Clear">
          <user name="admin" password="123" />
        </credentials>
      </forms>
</authentication>
.......

MVC框架有一个非常强大的功能称为Filters。这些都是Attributes,应用到一个Action方法或Controller类。当一个请求被处理的时候,这些Attributes引入了额外的逻辑。我们也可以定义自己的Filter。接下来给我们AdminController添加Filters(过滤器吧)!具体操作如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;

namespace SportsStore.WebUI.Controllers
{
    [Authorize]
    public class AdminController : Controller
    {
        private IProductRepository repository;
        public AdminController(IProductRepository repo)
        {
            this.repository = repo;
        }
.......   

添加了Filters(过滤器),然后我们在运行项目,结果如下图12.

图12.这就是我们使用Filters(过滤器)的结果。接下来我们需要一个验证者(程序),我们首先定义,身份验证提供者接口,在我们Web项目的Infrastructure/Abstract文件夹下创建接口("IAuthProvider"),具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SportsStore.WebUI.Infrastructure.Abstract
{
    public interface IAuthProvider
    {
        bool Authenticate(string username, string password);
    }
}

接着在Infrastructure文件夹里面再创建一个Concrete文件夹,添加一个实现类FormsAuthProvider,具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SportsStore.WebUI.Infrastructure.Abstract;
using System.Web.Security;

namespace SportsStore.WebUI.Infrastructure.Concrete
{
    public class FormsAuthProvider : IAuthProvider
    {
        public bool Authenticate(string username, string password) 
        {
            bool result = FormsAuthentication.Authenticate(username, password);
            if (result)
            {
                FormsAuthentication.SetAuthCookie(username, false);
            }
            return result;
        }
    }
}

然后在NinjectControllerFactory里面使用Ninject绑定,具体代码如下:

        private void AddBindings()
        {
            //绑定额外数据
            this.ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();

            EmailSettings emailSettings = new EmailSettings
            {
                WriteAsFile = bool.Parse(ConfigurationManager.AppSettings["Email.WriteAsFile"] ?? "false")
            };
            this.ninjectKernel.Bind<IOrderProcessor>().To<EmailOrderProcessor>()
                                                      .WithConstructorArgument("settings", emailSettings);
            //添加身份验证
            this.ninjectKernel.Bind<IAuthProvider>().To<FormsAuthProvider>();
        }

然后我们需要创建一个登录的视图模型类("LogOnViewModel")为了传递数据,具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace SportsStore.WebUI.Models
{
    public class LogOnViewModel
    {
        [Required]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}

然后在项目添加AccountController控制器类,具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.WebUI.Infrastructure.Abstract;
using SportsStore.WebUI.Models;

namespace SportsStore.WebUI.Controllers
{
    public class AccountController : Controller
    {
        IAuthProvider authProvider;
        public AccountController(IAuthProvider auth) 
        {
            this.authProvider = auth;
        }
        /// <summary>
        /// 登录页面
        /// </summary>
        /// <returns>View</returns>
        public ViewResult LogOn() 
        {
            return this.View();
        }
        /// <summary>
        /// Post请求登录页面
        /// </summary>
        [HttpPost]
        public ActionResult LogOn(LogOnViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (this.authProvider.Authenticate(model.UserName, model.Password))
                {
                    return this.Redirect(returnUrl ?? Url.Action("Index", "Admin"));
                }
                else
                {
                    ModelState.AddModelError("", "Incorrect username or password");
                    return this.View();
                }
            }
            else 
            {
                return this.View(); 
            }
        }
    }
}

接着,我们创建LogOn的视图,如下图13.

图13.创建好LogOn.cshtml页面后,具体代码如下:

@model SportsStore.WebUI.Models.LogOnViewModel

@{
    ViewBag.Title = "Admin:LogOn";
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}

<h1>Log In</h1>
<p>Please log in to access the administrative area:</p>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    @Html.EditorForModel()
    <p><input type="submit" value="Log In" /></p>
}

添加好我们的登录页面,运行程序如下图14.

图16.(这里只有输入我们在Web.comfig文件里配置的帐号密码方可登录进去)。接下来搞我们最后一个功能图片上传功能。首先我们必须给我们的数据表里面添加新的字段,具体如下图17.

图17.更改数据表,我们也要同步到我们的域模型,修改我们的Product模型如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;

namespace SportsStore.Domain.Entities
{
    public class Product : Object
    {
        [HiddenInput(DisplayValue = false)]
        public int ProductID { get; set; }

        [Required(ErrorMessage = "Please enter a product name")]
        public string Name { get; set; }

        [Required(ErrorMessage = "Please enter a description")]
        [DataType(DataType.MultilineText)]
        public string Description { get; set; }

        [Required]
        [Range(0.01, double.MaxValue, ErrorMessage = "Please enter a positive price")]
        public decimal Price { get; set; }

        [Required(ErrorMessage = "Please specify a category")]
        public string Category { get; set; }

        public byte[] ImageData { get; set; }

        [HiddenInput(DisplayValue = false)]
        public string ImageMimeType { get; set; }
    }
}

然后我们需要跟新到我们的实体模型,如给你给项目添加了数据模型,打开运行"自定义功能",VS就会自动帮你同步的,我这没有用数据模型的(*.edmx),所以我这里只需要更新域模型即可。创建用户的上传界面,上传图片习惯应该在编辑页面,所以修改我们的Edit.cshtml页面,代码如下:

@model SportsStore.Domain.Entities.Product

@{
    ViewBag.Title = "Admin:Edit" + @Model.Name;
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h1>Admin Edit @Model.Name</h1>
@using (Html.BeginForm("Edit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.EditorForModel()
    <div class="editor-label">Image</div>
    <div class="editor-field">
    @if (Model.ImageData == null)
    {
         @:None
    }
    else
    {
    <img width="150" height="150" src="@Url.Action("GetImage", "Product", new { Model.ProductID })" />
    }
    <div>Upload new image:<input type="file" name="Image" /></div>
    </div>
    <input type="submit" value="Save" />
    @Html.ActionLink("Cancel And Return To List", "Index")
}

接下来我们需要在AdminController的Edit Action(方法)保存我们的图片数据,具体修改如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;

namespace SportsStore.WebUI.Controllers
{
    [Authorize]
    public class AdminController : Controller
    {
        private IProductRepository repository;
        public AdminController(IProductRepository repo)
        {
            this.repository = repo;
        }
        /// <summary>
        /// 展示商品列表页面
        /// </summary>
        /// <returns>商品的列表</returns>
        public ViewResult Index()
        {
            return this.View(this.repository.Products);
        }
        /// <summary>
        /// 编辑方法
        /// </summary>
        /// <param name="productId">商品的ID</param>
        /// <returns>编辑后的商品</returns>
        public ViewResult Edit(int productId)
        {
            Product product = this.repository.Products.FirstOrDefault(h => h.ProductID == productId);
            return this.View(product);
        }
        [HttpPost]
        public ActionResult Edit(Product product, HttpPostedFileBase image)
        {
            if (ModelState.IsValid)
            {
                if (image != null)
                {
                    product.ImageMimeType = image.ContentType;
                    product.ImageData = new byte[image.ContentLength];
                    image.InputStream.Read(product.ImageData, 0, image.ContentLength);
                }
                this.repository.SaveProduct(product);
                //设置临时字典
                TempData["message"] = string.Format("{0} Has Been Saved", product.Name);
                return this.View(product);
                    //.RedirectToAction("Index");
            }
        }
        /// <summary>
        /// 创建商品
        /// </summary>
        /// <returns>新的商品</returns>
        public ViewResult Create()
        {
            return this.View("Edit", new Product());
        }
        /// <summary>
        /// 删除商品
        /// </summary>
        /// <param name="productID">商品的ID</param>
        /// <returns>URL从新指向列表</returns>
        [HttpPost]
        public ActionResult Delete(int productId)
        {
            Product prod = this.repository.Products.FirstOrDefault(h => h.ProductID == productId);
            if (prod!=null)
            {
                this.repository.DeleteProduct(prod);
                TempData["message"] = string.Format("{0} Was Deleted", prod.Name);
            }
            return this.RedirectToAction("Index");
        }
    }
}

OK,我们貌似还需要一个取出存贮图片的方法,在我们的ProductOntroller里添加GetImage Action(方法),具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Concrete;
using SportsStore.WebUI.Models;
using SportsStore.Domain.Entities;

namespace SportsStore.WebUI.Controllers
{
    public class ProductController : Controller
    {
        public int PageSize = 4; //设置一页显示多少商品
        private IProductRepository repository;
        public ProductController(IProductRepository productReposittory) 
        {
            this.repository = productReposittory;
        }
        //返回一个视图
        public ViewResult List(string category, int page = 1)
        {
            ProductsListViewModel viewModel = new ProductsListViewModel
            {
                Products = this.repository.Products
                                                .Where(h => category == null || h.Category == category)
                                                .OrderBy(h => h.ProductID)
                                                .Skip((page - 1) * PageSize)
                                                .Take(PageSize),
                PagingInfo = new PagingInfo
                {
                    CurrentPage = page,
                    ItemsPerPage = PageSize,
                    TotalItems = category == null ? this.repository.Products.Count() :
                    this.repository.Products.Where(h => h.Category == category).Count()
                },
                CurrentCategory = category
            };
            return this.View(viewModel);
        }
        //获取图片的方法
        public FileContentResult GetImage(int productId) 
        {
            Product prod = this.repository.Products.FirstOrDefault(h => h.ProductID == productId);
            if (prod != null)
            {
                return File(prod.ImageData, prod.ImageMimeType);
            }
            else 
            {
                return null;
            }
        }
    }
}

还记得我们在("EFProductRepository")实现保存方法的时候,我们只考虑到不存在商品的情况,也就是我们实际上就无法修改商品,现在我们在实现他商品存在修改的情况,具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SportsStore.Domain.Abstract;
using System.Data.Entity;
using SportsStore.Domain.Entities;

namespace SportsStore.Domain.Concrete
{
    public class EFProductRepository : IProductRepository
    {

        private EFDbContext context = new EFDbContext();
        public IQueryable<Product> Products
        {
            get { return this.context.Products; }
        }
        //实现接口里保存商品的方法
        public void SaveProduct(Product product) 
        {
            //不存在商品就新增
            if (product.ProductID == 0)
            {
                this.context.Products.Add(product);
            }
            else
            {
                //存在则修改
                this.context.Products.Attach(product);
                //EntityFramwork4.0修改的写法
                //this.context.ObjectStateManager.ChangeObjectState(product, System.Data.EntityState.Modified);
                //EntityFramwork4.1修改的写法
                this.context.Entry(product).State = System.Data.EntityState.Modified;
                
            }
            this.context.SaveChanges();
        }
        //实现接口的删除商品的方法
        public void DeleteProduct(Product product) 
        {
            this.context.Products.Remove(product);
            this.context.SaveChanges();
        }
    }

    //EFDbContext类可以使简单数据模型与数据库交互
    public class EFDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
    }
}

然后运行一下我们的Web程序,看看我们的上传功能到时是否OK。运行结果如下图18.

图17.OK说明我们的上传已经是没有问题的了!我们在后台上传图片前台肯定也需要一块地方展示商品图片,还还记我们的前台展示商品列表的页面好像用的是一个局部视图,那么我们就在这块局部视图中给商品图片分配一块位置,修改ProductSummary.cshtml页面,具体如下:

@model SportsStore.Domain.Entities.Product

@{
    ViewBag.Title = "ProductSummary";
}

<div class="item">
@if (Model.ImageData != null)
{
<div style="float:left;margin-right:20px">
<img width="75" height="75" src="@Url.Action("GetImage", "Product", new { Model.ProductID })" />
</div>
}
<h3>@Model.Name</h3>
@Model.Description
@using (Html.BeginForm("AddToCart","Cart"))
{
    @Html.HiddenFor(h=>h.ProductID)
    @Html.Hidden("returnUrl",this.Request.Url.PathAndQuery)
    <input type="submit" value="+ Add to cart" />
}
<h4>@Model.Price.ToString("C")</h4>
</div>

在前台分配好商品展示的地方,在后台上传好商品的图片然后运行,前台页面,运行结果如下图18.

图18.今天的后台就实战到这里,我的简单的购物流程也就暂时搞一个阶段了,后续我们在继续深入的学习MVC,几天的这篇文章写的真的很仓促,要是那里有写错还是描述错误的地方,还请各位前辈朋友多多批评指导,大家共同进步啊!在此,深表明哥指导学习。

源码包-->下载(这里稍后在放上)

转载于:https://www.cnblogs.com/HuiTai/archive/2012/07/12/MVC-10.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值