asp.net mvc 上传图片 摘自mvc 高级编程第311页

Image Uploads

I am going to complete the SportsStore user experience with something a little more sophisticated: I will add the ability for the

administrator to upload product images and store them in the database so that they are displayed in the product catalog. This isn‘t

something that is especially interesting or useful in its own right, but it does allow me to demonstrate some important MVC

Framework features.

Extending the Database

Open the Visual Studio Server Explorer window and navigate to the Products table in the database created in

Chapter 7. The name of the data connection may have changed to be EFDbContext, which is the name assigned to the

connection in the Web.config file. Visual Studio is a little bit inconsistent about when it renames the connection, so you

might also see the original name that was shown when the connection was created. Right-click on the Products table and

select New Query from the pop-up menu and enter the following SQL into the text area:

ALTER TABLE [dbo].[Products]

ADD [ImageData] VARBINARY (MAX) NULL,

[ImageMimeType] VARCHAR (50) NULL;

Click the Execute button (which is marked with an arrow) in the top-left cover of the window and Visual Studio will update

the database, adding two new columns to the table. To test the update, right-click on the Products table in the Server

Explorer window and select Open Table Definition from the menu. You will see that there are now columns

called ImageData and ImageMimeType, as shown in Figure 12-3.

Tip If the columns are not visible, close the design window, right-click on the data connection in the Server

Explorer window and select Refresh from the menu. The new columns should now be visible when you select the

Open Table Definition menu item again.

Enhancing the Domain Model

I need to add two new fields to the Products class in the SportsStore.Domain project that correspond to the new

database columns, as shown in Listing 12-10.

Listing 12-10. Adding Properties in the Product.cs File

using System.ComponentModel.DataAnnotations;

using System.Web.Mvc;

namespace SportsStore.Domain.Entities {

public class Product {

[HiddenInput(DisplayValue = false)]

public int ProductID { get; set; }

[Required(ErrorMessage = "Please enter a product name")]

public string Name { get; set; }

[DataType(DataType.MultilineText)]

[Required(ErrorMessage = "Please enter a description")]

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; }

public string ImageMimeType { get; set; }

}

}

Caution Make sure that the names of the properties that you add to the Product class exactly match the names you gave

to the new columns in the database.

Creating the Upload User Interface Elements

The next step is to add support for handling file uploads. This involves creating a UI that the administrator can use to upload an

image. Modify the Views/Admin/Edit.cshtml view so that it matches Listing 12-11.

Listing 12-11. Adding Support for Images in the Edit.cshtml File

@model SportsStore.Domain.Entities.Product

@{

312

ViewBag.Title = "Admin: Edit " + @Model.Name;

Layout = "∼/Views/Shared/_AdminLayout.cshtml";

}

<div class="panel">

<div class="panel-heading">

<h3>Edit @Model.Name</h3>

</div>

@using (Html.BeginForm("Edit", "Admin",

FormMethod.Post, new { enctype = "multipart/form-data" })) {

<div class="panel-body">

@Html.HiddenFor(m => m.ProductID)

@foreach (var property in ViewData.ModelMetadata.Properties) {

switch (property.PropertyName) {

case "ProductID":

case "ImageData":

case "ImageMimeType":

// do nothing

break;

default:

<div class="form-group">

<label>@(property.DisplayName ??

property.PropertyName)</label>

@if (property.PropertyName == "Description") {

@Html.TextArea(property.PropertyName, null,

new { @class = "form-control", rows = 5 })

} else {

@Html.TextBox(property.PropertyName, null,

new { @class = "form-control" })

}

@Html.ValidationMessage(property.PropertyName)

</div>

break;

}

}

<div class="form-group">

<div style="position:relative;">

<label>Image</label>

<a class=‘btn‘ href=‘javascript:;‘>

Choose File...

<input type="file" name="Image" size="40"

style="position:absolute;z-index:2;top:0;

left:0;filter: alpha(opacity=0); opacity:0;

backgroundcolor:

transparent;color:transparent;"

onchange=‘$("#upload-fileinfo").

html($(this).val());‘>

</a>

<span class=‘label label-info‘ id="upload-file-info">

</span>

</div>

@if (Model.ImageData == null) {

313

<div class="form-control-static">No Image</div>

} else {

<img class="img-thumbnail" width="150" height="150"

src="@Url.Action("GetImage", "Product",

new { Model.ProductID })" />

}

</div>

</div>

<div class="panel-footer">

<input type="submit" value="Save" class="btn btn-primary" />

@Html.ActionLink("Cancel and return to List", "Index", null, new {

@class = "btn btn-default"

})

</div>

}<

/div>

You may already be aware that Web browsers will upload files properly only when the HTML form element defines an

enctype value of multipart/form-data. In other words, for a successful upload, the form element must look

like this:

...

<form action="/Admin/Edit" enctype="multipart/form-data" method="post">

...

Without the enctype attribute, the browser will transmit only the name of the file and not its content, which is no use at all.

To ensure that the enctype attribute appears, I must use an overload of the Html.BeginForm helper method that lets

me specify HTML attributes, like this:

...

@using (Html.BeginForm("Edit", "Admin",

FormMethod.Post, new { enctype = "multipart/form-data" })) {

...

There are two other changes in the view. The first is that I have replaced the Razor if expression I used when generating

input elements with a switch statement. The effect is the same, but it allows me to specify the model properties I want to

skip more concisely, and I don’t want to display the image-related properties directly to the user.

Instead, I have made the remaining change, which is to add an input element whose type is file to allow file upload, along

with an img element to display the image associated with a product, if there is one in the database.

The horrific mess of inline CSS and JavaScript addresses a shortcoming in the Bootstrap library: it does not properly style file

input elements. There are a number of extensions that add the missing functionality, but I have chosen the magic incantation

shown in the listing because it is self-contained and is reliable. It doesn’t change the way that the MVC Framework works, just the

way in which the elements in the Edit.cshtml file are styled.

Saving Images to the Database

I need to enhance the POST version of the Edit action method in the Admin controller so that I take the image data that has

been uploaded and save it in the database. Listing 12-12 shows the changes that are required.

Listing 12-12. Handling Image Data in the AdminController.cs File

using System.Linq;

using System.Web;

using System.Web.Mvc;

using SportsStore.Domain.Abstract;

314

using SportsStore.Domain.Entities;

namespace SportsStore.WebUI.Controllers {

[Authorize]

public class AdminController : Controller {

private IProductRepository repository;

public AdminController(IProductRepository repo) {

repository = repo;

}

public ViewResult Index() {

return View(repository.Products);

}

public ViewResult Edit(int productId) {

Product product = repository.Products

.FirstOrDefault(p => p.ProductID == productId);

return View(product);

}

[HttpPost]

public ActionResult Edit(Product product, HttpPostedFileBase image

= null) {

if (ModelState.IsValid) {

if (image != null) {

product.ImageMimeType = image.ContentType;

product.ImageData = new byte[image.ContentLength];

image.InputStream.Read(product.ImageData, 0,

image.ContentLength);

}

repository.SaveProduct(product);

TempData["message"] = string.Format("{0} has been saved",

product.Name);

return RedirectToAction("Index");

} else {

// there is something wrong with the data values

return View(product);

}

}

public ViewResult Create() {

return View("Edit", new Product());

}

[HttpPost]

public ActionResult Delete(int productId) {

Product deletedProduct = repository.DeleteProduct(productId);

if (deletedProduct != null) {

TempData["message"] = string.Format("{0} was deleted",

deletedProduct.Name);

}

return RedirectToAction("Index");

}

315

}

}

I have added a new parameter to the Edit method, which the MVC Framework uses to pass the uploaded file data to the

action method. I check to see if the parameter value is null; if it is not, I copy the data and the MIME type from the parameter

to the Product object so that it is saved to the database. I must also update the EFProductRepository class in the

SportsStore.Domain project to ensure that the values assigned to the ImageData and ImageMimeType

properties are stored in the database. Listing 12-13 shows the required changes to the SaveProduct method.

Listing 12-13. Ensuring That the Image Values Are Stored in the Database in the EFProductRepository.cs File

...

public void SaveProduct(Product product) {

if (product.ProductID == 0) {

context.Products.Add(product);

} else {

Product dbEntry = context.Products.Find(product.ProductID);

if (dbEntry != null) {

dbEntry.Name = product.Name;

dbEntry.Description = product.Description;

dbEntry.Price = product.Price;

dbEntry.Category = product.Category;

dbEntry.ImageData = product.ImageData;

dbEntry.ImageMimeType = product.ImageMimeType;

}

}

context.SaveChanges();

}.

..

Implementing the GetImage Action Method

In Listing 12-11, I added an img element whose content was obtained through a GetImage action method on the

Product controller. I am going to implement this action method so that I can display images contained in the database. Listing

12-14 shows the definition of the action method.

Listing 12-14. The GetImage Action Method in the ProductController.cs File

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using SportsStore.Domain.Abstract;

using SportsStore.Domain.Entities;

using SportsStore.WebUI.Models;

namespace SportsStore.WebUI.Controllers {

public class ProductController : Controller {

private IProductRepository repository;

public int PageSize = 4;

public ProductController(IProductRepository productRepository) {

316

this.repository = productRepository;

}

public ViewResult List(string category, int page = 1) {

ProductsListViewModel model = new ProductsListViewModel {

Products = repository.Products

.Where(p => category == null || p.Category ==

category)

.OrderBy(p => p.ProductID)

.Skip((page - 1) * PageSize)

.Take(PageSize),

PagingInfo = new PagingInfo {

CurrentPage = page,

ItemsPerPage = PageSize,

TotalItems = category == null ?

repository.Products.Count() :

repository.Products.Where(e => e.Category ==

category).Count()

},

CurrentCategory = category

};

return View(model);

}

public FileContentResult GetImage(int productId) {

Product prod = repository.Products

.FirstOrDefault(p => p.ProductID == productId);

if (prod != null) {

return File(prod.ImageData, prod.ImageMimeType);

} else {

return null;

}

}

}

}

This method tries to find a product that matches the ID specified by the parameter. The FileContentResult class is

used as the result from an action method when you want to return a file to the client browser, and instances are created using the

File

时间: 2024-10-01 06:20:55

asp.net mvc 上传图片 摘自mvc 高级编程第311页的相关文章

解读经典《C#高级编程》泛型 页114-122.章4

前言 本章节开始讲解泛型..Net从2.0开始支持泛型,泛型不仅是C#的一部分,也与IL代码紧密集成.所以C#中泛型的实现非常优雅.相对于C#,Java是后期引入的泛型,受限于最初的设计架构,就实现的比较别扭,遭到不少人的吐槽,比如"类型擦除"问题.使用C#还是幸福的. 使用泛型最典型的应用,可能是List<T>了,从List<T>我们可以看到,使用泛型最明显的优点是: 将List的功能和包含类T的功能分开,功能各自实现.使得代码内聚性.复用性.灵活性都更好.

Asp.net mvc 4.0 高级编程 百度云下载

Asp.net mvc 4.0 高级编程 百度云下载地址:链接:http://pan.baidu.com/s/1o6zFvOe 密码:xyss 1.基于 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发 2.采用MVC的框架模式,具有耦合性低.重用性高.生命周期成本低.可维护性高.有利软件工程化管理等优点 3.采用WebAPI,客户端完全摆脱了代理和管道来直接进行交互 4.采用EasyUI前台UI界面插件,可轻松的打造出功能丰富并且美观的UI

C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)

译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# 6 and .NET Core 1.0>.水平有限,各位阅读时仔细分辨,唯望莫误人子弟. 附英文版原文:Professional C# 6 and .NET Core 1.0 - Chapter 41 ASP.NET MVC ------------------------------------ 本

[渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序使用高级功能

这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十二篇:为ASP.NET MVC应用程序使用高级功能 原文:Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application 译文版权所有,谢绝全文转载--但您可以在您的网站上添加到该教程的链接. 在之前的教程中,您已经实现了继承.本教程引入了当你在使用实体框架Code

ASP.NET MVC中有关AOP的编程

AOP(Aspect oriented programming)面向切面编程,主要意思是把相同.相似的并且零散的逻辑抽离出来,统一处理,这样不仅维护起来方便,也使得代码更加关注自己本身,清晰明了. 比如我们常见的权限检查,验证登陆,异常处理等都是散乱在系统各个地方,比如管理员在登陆状态才可以添加一个学生信息: public ActionResult AddStudent(Student student) { if (currentUser != null) { StudentDAL.Add(st

Asp.Net MVC上传图片

mvc上传图片 [HttpPost] public JsonResult Upload() { if (Request.Files.Count > 0) { if (Request.Files.Count == 1) { HttpPostedFileBase file = Request.Files[0]; if (file.ContentLength > 0) { string title = string.Empty; title = DateTime.Now.ToString("

ASP.NET MVC5 高级编程 第2章 控制器

参考资料<ASP.NET MVC5 高级编程>第5版 第2章 控制器 控制器:响应用户的HTTP 请求,并将处理的信息返回给浏览器. 2.1 ASP.NET MVC 简介 MVC 模式中的控制器(controller)主要负责响应用户的输入,并且在响应时修改(Model).通过这种方式,MVC 中的Controller 主要关注的是应用程序流,输入数据的处理,以及对相关视图(View)数据来源的提供 MVC 模式中 URL 首先告诉路由去实例化哪个控制器,调用哪个方法,并为该方法提供需要的参数

ASP.NET MVC5 高级编程 第5章 表单和HTML辅助方法

参考资料<ASP.NET MVC5 高级编程>第5版 第5章 表单和HTML辅助方法 5.1 表单的使用 5.1.1 action 和 method 特性 默认情况下,表单发送的是 HTTP Post 请求 EF 对于外键关系,数据库名称等也有约定.这些约定取代了以前需要提供给一个关系对象映射框架的所有映射和配置. GET 方法:GET 请求的所有参数都在URL中,因此可以为GET 请求建立书签. POST 方法:浏览器把输入值放入 HTTP 请求的主体中. 5.2 辅助方法 可以通过视图的H

Configuring Autofac to work with the ASP.NET Identity Framework in MVC 5

https://developingsoftware.com/configuring-autofac-to-work-with-the-aspnet-identity-framework-in-mvc-5 Configuring Autofac to work with the ASP.NET Identity Framework in MVC 5 By Tony Mackay  02 February 2015 This post will show you how to modify the