ASP.NET MVC 文档示例 第二部分






4.84/5 (15投票s)
ASP.NET MVC 文档示例 的第二部分
引言
这篇文章是 ASP.NET MVC 文档示例 的第二部分,如果您还没有阅读过,请先查看
https://codeproject.org.cn/Articles/755459/ASP-NET-MVC-Documents-Sample
在这一部分,我们将扩展之前的构建版本。基本上,我们想要按照我们的意愿显示数据。

上面是我们想要的文档视图的截图。
使用一段时间后,数据库中将会有很多文档和公司记录,我们不希望它们全部显示在一个页面上,所以我们必须添加分页。方便的是,我们可以搜索特定的公司,而不是手动翻阅所有公司来查找我们正在寻找的公司,所以我们必须向应用程序添加搜索功能。当我们向数据库输入新公司并返回列表时,公司不会按字母顺序排列,所以我们必须编写一些代码使其按字母顺序排序。然后,还有我们不希望任何人看到我们的文档的事实,所以我们必须确保只有登录的用户才能查看它们。我们也必须将其构建进去。而且,我们希望上传我们在邮件中收到的实际文档的扫描件,并将它们作为 .PDF 提供在我们的应用程序中。因此,我们需要为此创建一个上传功能,并创建一个链接在浏览器中查看这些文档。
总而言之
- 
    创建分页
- 
    添加搜索功能
- 
    添加字母排序
- 
    使其私有
- 
    创建上传功能。
- 
    验证
这就是我们将在这一部分中要做的事情。
背景
本文不会讨论 MVC 模型本身或控制器如何工作等,因为其他文章已经对此有很多论述。我写这篇文章的主要目的是向刚开始编程的人展示如何从零开始构建一个功能齐全的动态 Web 应用程序。我所说的动态数据是指 HTML 代码中不会有静态列表,列表中的所有数据都来自数据库,并在需要时可以更改。
使用代码
我使用 Visual Studio 2012 Professional 构建了这个示例,然后又在 Visual Studio 2013 Ultimate 90 天试用版中进行了测试,以查看它是否按预期工作,因此您也可以使用该版本。
重要提示:请确保已安装 EntityFramework。要找出是否安装,请在解决方案资源管理器中单击已创建的项目,然后转到“管理 NuGet 程序包...”,在下一个屏幕中选择“全部”,如果它不在列表中,请转到左侧的“联机”选项,您将获得可用程序包列表,选择 EntityFramework 并单击“安装”,项目将添加一个引用。
您可以从我的 OneDrive 下载该项目
https://onedrive.live.com/redir?resid=CDF4A34C128AE7C4%213254
在 OneDrive 中单击 MvcDocuments Sample,然后选择下载
 
 
1. 创建分页
我们要做的第一件事是向应用程序添加引用,为此,请转到 Visual Studio 中的“工具”菜单,选择“NuGet 程序包管理器”,然后在其中选择“管理解决方案的 NuGet 程序包...”选项,如下图所示。

您将看到以下屏幕
 
选择左侧的“联机”选项卡,然后在右上角的搜索框中输入:PagedList,您将看到上面显示的搜索结果,如果您单击“安装”,该 PagedList 将添加到解决方案中。在解决方案资源管理器中查看并展开“引用”文件夹,您将看到已添加 PagedList 库的引用,如下图所示。

现在我们可以使用 PagedList 并将分页添加到我们的应用程序中。为此,我们将更改一些代码,让我们从在应用程序的文档部分实现分页开始。
您还记得在 MVCDocuments Sample 的第一部分中,我们创建了控制器,我们根本没有触碰这些控制器,但现在我们要更改 DocumentController.cs 代码的一部分。请转到解决方案资源管理器,展开“控制器”文件夹,找到 DocumentController.cs 文件并打开它。
我们将向我们刚刚在上一部分中添加的 PagedList 库文件添加一个 using 引用,并使用 PagedList 库。
首先,在类的“using”部分添加 using PagedList;,如下所示,//已添加
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Web; using System.Web.Mvc; using PagedList; //Added using MvcDocuments.Models;
然后转到以下代码部分
public ActionResult Index()
{
   var documents = db.Documents.Include(d => d.Company).Include
   (d => d.Mail_category).Include(d => d.Costs_group).Include(d => d.Payment_status);
   return View(documents.ToList());
}
我们将把这段代码改为这样
public ViewResult Index(int? page)
{
   var documents = db.Documents.Include(d => d.Company).Include
  (d => d.Mail_category).Include(d => d.Costs_group).Include
  (d => d.Payment_status).OrderByDescending(d => d.Document_date);
  //Pager
  int pageSize = 2;
  int pageNumber = (page ?? 1);
  //Return content
  return View(documents.ToPagedList(pageNumber, pageSize));
}
正如您所见,很多地方都发生了变化,这个方法从 ActionResult 变成了 ViewResult,并且通过以下方式添加了排序顺序:
.OrderByDescending(d => d.Document_date);
分页器的代码已添加。正如您所见,pageSize 设置为 2,因此每页显示两条记录,但您可以更改它(我设置的值为 2 是为了测试目的)。请注意,return View 已更改为:Documents.ToPagedList(...),因此将返回一个 Paged List。
在对 DocumentController.cs 文件代码进行这些更改后,转到解决方案资源管理器,展开“视图”文件夹,然后转到 Index.cshtml 文件并打开它。

在此 Index.cshtml 页面的代码顶部,您会看到这一行
@model IEnumerable<MvcDocuments.Models.Document>
将此代码更改为如下所示
@model PagedList.IPagedList<MvcDocuments.Models.Document>
现在在代码中查找 <tr> 部分以及以下类型的代码
<th>
          @Html.DisplayNameFor(model => model.Document_date)
</th>
这段代码无法与 PagedList 一起工作,所以我们将把所有这些都改为以下内容
<tr>
 <th>
     Document Date:
 </th>
 <th>
     Company Name:
 </th>
 <th>
     Mail Category:
 </th>
 <th>
     Costs Group:
 </th>
 <th>
     Payment Status:
 </th>
 <th>
     Reference:
 </th>
 <th>
     Note:
 </th>
 <th>
     Amount Ex VAT:
 </th>
 <th>
     VAT:
 </th>
 <th>
     Amount:
 </th>
 <th>
     URI;
 </th>
</tr>
完成后,转到页面底部,在 </table> 之后添加以下代码
<div> 
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)of @Model.PageCount 
@if (Model.HasPreviousPage)
{
    @Html.ActionLink("<<", "Index", new { page = 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
    @Html.Raw(" ");
    @Html.ActionLink("< Prev", "Index", new { page = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
}
else
{
@:<<
@Html.Raw(" ");
@:< Prev
}
@if (Model.HasNextPage)
{
@Html.ActionLink("Next >", "Index", new { page = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
@Html.Raw(" ");
@Html.ActionLink(">>", "Index", new { page = Model.PageCount, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter })
}
else
{
@:Next >
@Html.Raw(" ")
@:>> 
}
</div>
现在转到 Visual Studio 中的“生成”菜单选项,单击“重新生成解决方案”选项,然后按 F5。如果您已完成以上步骤并转到“文档”,您将看到此视图
 
 
我还没有向这个示例添加记录,但如果您的 Documents 数据库中有两条以上的记录,分页功能就会起作用。
正如您所见,添加分页功能需要对您想要应用分页的所有页面进行一些工作。
2. 添加搜索功能
接下来我们要做的就是添加一些搜索功能,第一步是在视图页面上进行,所以打开 Index.cshtml 页面,并在 <table> 部分开始之前添加以下代码
@using (Html.BeginForm())
{
   <p> Find Relation: @Html.TextBox("SearchString")
   <input type="submit" value="Find" /> </p>
}
<table>...
这将在页面上显示一个搜索框和一个带有“查找”文本的按钮。Index.cshtml 页面就到这里,再次转到解决方案资源管理器并打开 DocumentController.cs 文件。
 
 
更改 ViewResult Index(返回 Index 页面的方法),使其如下代码所示
public ViewResult Index(string sortOrder, string currentFilter , string searchString , int? page)
{
   ViewBag.CurrentSort = sortOrder;
   ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";
if (Request.HttpMethod == "GET")
{
   searchString = currentFilter;
}
else
{
page = 1;
}
ViewBag.CurrentFilter = searchString;
var document = from d in db.Documents
select d;
if (!String.IsNullOrEmpty(searchString))
{
   document = document.Where(d => d.Company.Company_name.ToUpper().Contains(searchString.ToUpper()));
}
switch (sortOrder)
{
  case "Date":
  document = document.OrderBy(d => d.Document_date);
  break;
  case "Date desc":
  document = document.OrderByDescending(d => d.Document_date);
  break;
  default:
  document = document.OrderByDescending(d => d.Document_date);
  break;
}
//Pager
int pageSize = 2;
int pageNumber = (page ?? 1);
//Return content
return View(document.ToPagedList(pageNumber, pageSize));
}
当您按下 F5 按钮并转到“文档”页面时,您会看到搜索框和按钮已添加。输入您某个客户的姓名或几个首字母,就像我一样(co 代表 CodeProject),您将只获得来自该客户的记录。
 
 
任务:好的,现在是时候将分页和搜索功能添加到您的页面和控制器中了,因为我希望这个示例能够正常工作,所以我已经在提供的示例中的“联系人”、“公司”和“文档”页面和控制器中完成了这些,但如果您愿意,可以自己完成上述步骤。
3. 添加字母排序
正如您可能在前一张图像中注意到的那样,文档是按降序日期排序的,因此最新的记录在顶部,如果文档中输入了时间,例如 2014/04/25 14:57,排序也将基于时间进行,因此最新的文档将在顶部。
对于文档,我们希望按日期排序,但对于公司,我们希望它们按字母顺序排列。
当您打开 CompaniesController.cs 文件时
public ActionResult Index()
{
   var companies = db.Companies.Include(c => c.State).Include(c => c.Country);
   return View(companies.ToList());
}
并在 .Include(c => c.Country); 部分后面添加以下代码
.OrderBy(c => c.Company_name)
所以代码看起来像这样
public ActionResult Index()
{
  var companies = db.Companies.Include(c => c.State).Include(c => c.Country).OrderBy(c => c.Company_name);
  return View(companies.ToList());
}
您将看到按字母顺序进行的排序。
注意:在上面显示的的代码中,我们没有向 CompanyController.cs 和 View 文件夹中的 Company 视图的 Index.cshtml 文件添加搜索功能,在 MVCDocuments Sample part 2 下载中也添加了搜索功能。
任务:上面显示的的代码是在您向其添加分页和搜索功能之前的代码,因此如果您完成了前面的任务,您的代码应该会有所不同,但您知道在哪里可以为代码添加排序顺序,并且在提供的示例代码中也实现了这一点。
4. 使其私有
接下来我们要做的就是让页面私有,这样只有登录的用户才能查看页面。我们回到解决方案资源管理器,打开 Document 文件夹,然后打开 Index.cshtml 页面。在 <h2>Index</h2> 标签的正下方输入以下代码行
<h2>Index</h2>
@if(User.Identity.IsAuthenticated) {
<span>
现在转到页面底部,在 </div> 的闭合标签下方添加以下代码
</span>
} else 
{
  <span>You have to Login to View my Documents</span>
}
当您现在按 F5 并转到“文档”时,您将看到以下屏幕
 
 
注意:如果您看到文档,那么您很可能已登录。当然,任何注册的人都可以查看您在此示例中的记录,但如果您删除了注册选项,则记录就是私有的。
任务:现在将所有页面都设为私有,因此不仅是 Index.cshtml 页面,而是每个文件夹中的所有页面。
5 创建上传功能
我们要做的第一件事是创建一个文件夹,我们将在此文件夹中接收上传的文件。转到解决方案资源管理器,右键单击它,选择“添加”,然后选择“新建文件夹”。
给这个文件夹命名为:Assets,完成后,将有一个新文件夹添加到解决方案中。
 
 
现在右键单击 Assets 文件夹,再次选择“添加”,然后选择“新建文件夹”,并将其命名为:Documents,使其看起来像这样。

现在转到 Views 文件夹,然后转到 Document 文件夹,右键单击它,选择“添加视图”。将这个新视图命名为:DocumentUpload,不要更改其他任何内容,只需单击“添加”按钮。

将创建 DocumentUpload.cshtml 文件,您将看到此代码
@{
   ViewBag.Title = "DocumentUpload";
}
<h2>DocumentUpload</h2>
我们将把这段代码改为以下内容
@@{
   ViewBag.Title = "Upload Document";
}
@if(User.Identity.IsAuthenticated) {
<span>
<h2>Upload Document</h2>
<form action="" method="post" enctype="multipart/form-data">
 <table>
  <td>
   <label for="file">Filename</label></td>
  <td> 
   <input type="file" name="file" id="file" />
  </td>
  <td>
   <input type="submit" value="Upload" />
  </td>
 </table>
</form>
</span>
} else 
{
 <span>You need to Login to View this page!</span>
}
上传页面将看起来像这样
 
 
页面就到这里了,现在打开 Document 文件夹中的 Index.cshtml 页面,找到这部分代码
<p>
   @Html.ActionLink("Create New", "Create")
</p>
将此部分更改为
<p>
  @Html.ActionLink("Create New", "Create") @Html.ActionLink("Upload Document", "DocumentUpload")
</p>
这将显示上传页面的链接

页面就到这里了,现在转到解决方案资源管理器中的 Controllers 文件夹,转到 DocumentController.cs 文件并打开它。转到 using 部分,并添加以下 using 指令:using System.IO;,使其与下面显示的一致。
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Web; using System.Web.Mvc; using PagedList; using System.IO; using MvcDocuments.Models;
现在转到此 DocumentController 所有代码的底部,并将以下代码添加到这部分后面
protected override void Dispose(bool disposing)
{
  db.Dispose();
  base.Dispose(disposing);
} 
所以在闭合的:} (花括号) 之后,输入此代码
public ActionResult DocumentUpload()
{
  return View();
}
[HttpPost]
public ActionResult DocumentUpload(HttpPostedFileBase file)
{
  string path = null;
  if (file.ContentLength > 0)
  {
   var fileName = Path.GetFileName(file.FileName);
   path = AppDomain.CurrentDomain.BaseDirectory + "Assets\\Documents\\" + fileName;
   Response.Write(path.ToString());
   file.SaveAs(path);
  }
  return RedirectToAction("Index");
}
public ActionResult OpenFile()
{
 return View();
}
现在转到解决方案资源管理器文件夹,打开 View 文件夹,选择 Index.cshtml 文件,找到这行代码
<td> @Html.DisplayFor(modelItem => item.Document_uri) </td>
将此代码更改为与下面显示的一致
<td> @Html.DisplayFor(modelItem => item.Document_uri) <a href="~/Assets/Documents/@Html.DisplayFor(model => item.Document_uri)"target="_blank">View Document</a> </td>
这将为页面上的上传文档添加一个链接。请注意,预期的过程是扫描您通过标准邮件收到的文档,将其保存为 .PDF 格式,然后上传。您必须按原样命名文档,例如,如果您有一个名为 Manual1246.PDF 的文档,您必须确保 .PDF 文件扩展名位于 .PDF 文档名称之后。
单击链接后,您将看到上传的 .PDF 文档。
 
 
我还有一件事做了,那就是更改了以下代码,使页面显示不同的标题
@{
  ViewBag.Title = "Documents";
}
<h2>Documents</h2>
我已将 ViewBag.Title 改为“Documents”,使其显示该标题,并将 <h2> 部分更改为显示“Documents”而不是“Index”,并且我还对 Contact 和 Company 也做了同样的处理,这样在使用应用程序时可以更清楚地知道您在哪个页面上。
6 添加验证
我还有一件事想添加到应用程序中,那就是确保所有字段都已填写,这样就不会将空数据传递到数据库,所以我更改了类。请查看 Document.cs 类(在解决方案资源管理器中的 Models 文件夹中),并将其更改为如下所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcDocuments.Models
{
 public class Document
 {
  //Identifier
  public int DocumentId { get; set; }
  //Document date
  [Required]
  public DateTime Document_date { get; set; }
  //Company
  public int CompanyId { get; set; }
  public virtual Company Company { get; set; }
  //Mail category
  public int Mail_categoryID { get; set; }
  public virtual Mail_category Mail_category { get; set; }
  //Costs group
  public int Costs_groupId { get; set; }
  public virtual Costs_group Costs_group { get; set; }
  //Payment status
  public int Payment_statusId { get; set; }
  public virtual Payment_status Payment_status { get; set; }
  //Bill
  [Required]
  public string Reference { get; set; }
  //Note
  [Required]
  public string Note { get; set; }
  //Financial
  [Required]
  public double AmoutExVat { get; set; }
  [Required]
  public double Vat { get; set; }
  [Required]
  public double Amount { get; set; }
  //.PDF Link
  [Required]
  public string Document_uri { get; set; }
 }
}
正如您所见,我们添加了以下 Using 指令:
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema;
并且我们在变量上方添加了
[Required]
如果您也这样做了并按 F5,您将收到一个错误,表明内容已更改,所以我们必须先更新数据库。为此,我们回到我们在本示例第一部分中使用过的程序包管理器控制台(工具 > NuGet 程序包管理器 > 程序包管理器控制台),然后输入:
PM> Add-Migration "DatabaseChanged"
在“”之间,您可以输入任何您想要的名称,这只是您给这个迁移起的名称。然后按 Enter 键,迁移将在解决方案资源管理器中的 Migrations 文件夹中创建。
现在,在程序包管理器控制台中输入:
PM> Update-Database
数据库将被更新,当您现在转到“文档”并选择“新建”,然后单击“创建”按钮时,您将看到此屏幕。

明确一点。当您更改 Model 文件夹中的类时,您必须执行添加迁移的这些步骤,否则将无法正常工作。如果出现问题并且更新数据库失败,只需删除迁移并重新开始。还有一件事我想更改,那就是在您创建新文档、联系人或任何使用列表的地方,列表的排序方式。
让我们看一下 DocumentController.cs 文件中的 Create 方法,它看起来像这样:
public ActionResult Create()
{
  ViewBag.CompanyId = new SelectList(db.Companies,"CompanyId", "Company_name");
  ViewBag.Mail_categoryID = new SelectList(db.Mail_categories, "Mail_category_name");
  ViewBag.Costs_groupId = new SelectList(db.Costs_groups, "Costs_groupId", "Cost_group_name");
  ViewBag.Payment_statusId = new SelectList(db.Payment_statusses, "Payment_statusId", "Payment_status_name");
  return View();
}
我们必须将代码更改为与以下内容匹配:
public ActionResult Create()
{
  ViewBag.CompanyId = new SelectList(db.Companies.OrderBy(x => x.Company_name), "CompanyId", "Company_name");
  ViewBag.Mail_categoryID = new SelectList(db.Mail_categories.OrderBy(x => x.Mail_category_name), "Mail_categoryId", "Mail_category_name");
  ViewBag.Costs_groupId = new SelectList(db.Costs_groups.OrderBy(x => x.Cost_group_name), "Costs_groupId", "Cost_group_name");
  ViewBag.Payment_statusId = new SelectList(db.Payment_statusses.OrderBy(x => x.Payment_status_name), "Payment_statusId", "Payment_status_name");
  return View();
}
这个 .OrderBy(x => x.Cost_group_name) 负责按字母顺序呈现列表。

这就是 MVCDocuments Sample 的这一部分的内容。希望您到目前为止喜欢我的写作,也许这个应用程序对您来说有一些实际用途。
关注点
这就是 MVCDocuments Sample 的这一部分的内容。希望您到目前为止喜欢我的写作(我正在考虑下一部分关于使用 Html5 和 JavaScript 使其外观更漂亮的内容)。希望这个应用程序对您来说有一些实际用途。我的个人版本存储了大约一千份 .PDF 格式的文档,我经常使用它来查找信息。
历史
这是 ASP.NET MVC Documents Sample 的第一个版本。

