WCF RESTful 服务和 ASP.NET MVC 5 中的 WebGrid - 第 2 部分






4.88/5 (20投票s)
在本文中,我们将学习如何创建 WCF RESTful 服务,并在 ASP.NET MVC 5 应用程序中使用 WebGrid 控件来消耗这些服务。
注意:要使用此处附加的代码,必须运行在第一部分创建的 WCF 服务。
引言
这是文章的第二部分,共两部分。在第一部分中,我们创建了 WCF RESTful 服务,将在本部分中使用。在本第二部分中,我们将创建一个带有 WebGrid 控件的 ASP.NET MVC Web 应用程序,并执行 CRUD 操作。
如果您尚未阅读第一部分,我建议您先访问那里,因为它将为您提供更好的背景信息,并在您阅读本文时提供帮助。以下是本文第二部分的概述:
- 创建 ASP.NET MVC 5 应用程序
- 在 WebGrid 控件中显示数据
- 添加内联编辑操作
- 添加内联删除操作
- 添加创建操作
创建 ASP.NET MVC 5 应用程序
除了本文,我们还将创建一个演示 MVC 应用程序,该应用程序将对客户数据执行 CRUD 操作。客户数据将显示在 WebGrid 中,用户将在其中执行创建、读取、更新(编辑)和删除操作。当用户在客户端(浏览器)执行任何操作时,调用将转到 MVC 应用程序 Controller 的特定 Action 方法。然后 Action 方法将调用第一部分中创建的 WCF RESTful Web 服务。最后,WCF Web 服务会调用存储库以对数据库执行适当的操作来持久化更改。
请按照以下步骤创建演示应用程序:
- 让我们开始创建一个示例应用程序,选择 ASP.NET Web 应用程序模板,将项目命名为 DemoMVCApp,然后单击“确定”。
- 现在,选择 MVC 模板,如下所示,然后单击“确定”。
Visual Studio 将为我们创建一个 ASP.NET MVC 项目结构。我们将在接下来的步骤中修改它以实现所需的功能。
- 在 Models 文件夹下,添加一个名为 Customer 的类,并在其中写入以下代码,如下所示:
public class Customer { public int CustomerId { get; set; } [Required] [DisplayName("Name")] public string CustomerName { get; set; } [Required] [DisplayName("Address")] public string CustomerAddress { get; set; } } }
- 在 Controller 文件夹下,添加一个名为 CustomerController 的控制器。此控制器将具有 Customer 模型的 Get、Post、Put 和 Delete 操作的方法。在 CustomerController 类中,写入以下代码:
readonly string customerServiceUri = "https://:1750/CustomerService.svc/"; // customerServiceUri is a global variable for this customercontroller, having the path of CustomerService. // Please change URI path if service is hosed at some different URI in your case. public ActionResult Index() { List<Customer> customerList = new List<Customer>(); using (WebClient webClient = new WebClient()) { string dwml; dwml = webClient.DownloadString(customerUri + "GetAllCustomers"); customerList = JsonConvert.DeserializeObjectAsync<List<Customer>>(dwml).Result; } return View(customerList); }
我们刚刚实现了一个名为 Index 的 Action 方法,该方法调用 WCF 服务,反序列化接收到的数据,并返回客户列表。
在 WebGrid 控件中显示数据
- 通过右键单击 CustomerController 中的 Index 方法并将其命名为 Index 来添加视图。它将在 Views > Customer 文件夹下添加一个 Index.cshtml 文件。在 Index 视图中写入以下代码。此代码将创建一个 WebGrid,并将数据绑定到该网格。我们直接引用脚本和 CSS 文件。(此处我们不关注打包和最小化功能。)
注意:所有自定义 CSS 都写在 Content 文件夹下的 index.css 文件中,自定义脚本写在 Scripts 文件夹下的 index.js 文件中。请在相应的文件夹中创建这些文件,相应地编写代码,并在 Index 页面中进行引用。警告:将 index.js 的引用放在页面末尾。@model IEnumerable<DemoMVCWebApp.Models.Customer> <script src="~/Scripts/jquery-1.10.2.min.js"></script> <link href="~/Content/index.css" rel="stylesheet" /> @{ var grid = new WebGrid(Model, canPage: true, rowsPerPage: 5, selectionFieldName: "selectedRow"); grid.Pager(WebGridPagerModes.NextPrevious);} <div id="gridContent"> @grid.GetHtml(tableStyle: "webGrid", headerStyle: "header", alternatingRowStyle: "alt", selectedRowStyle: "select", rowStyle: "webgrid-row-style", columns: grid.Columns( grid.Column("CustomerId", "Customer Id", @<text> <span id="spnCustomerId">@item.CustomerId</span></text>, canSort: false), grid.Column("CustomerName", "Customer Name", format: @<text> <span id="spnCustomerName" class="display-mode">@item.CustomerName</span> <input type="text" id="CustomerName" value="@item.CustomerName" class="edit-mode"/></text>, canSort: false), grid.Column("CustomerAddress", "Customer Address", format: @<text> <span id="spnCustomerAddress" class="display-mode">@item.CustomerAddress</span> <input type="text" id="CustomerAddress" value="@item.CustomerAddress" class="edit-mode"/></text>, canSort: false), grid.Column("Action", format: @<text> <img src="~/Content/images/edit.jpg" title="Edit Customer" id="btnEdit" class="edit-button"/> <img src="~/Content/images/delete.jpg" title="Delete Customer" class="delete-customer"/> </text>, style: "width:220px", canSort: false) )) </div>
- 在 App_Start 文件夹下的 RoutConfig.cs 文件中,按如下方式设置默认路由:
defaults: new { controller = "Customer", action = "Index", id = UrlParameter.Optional }
- 运行应用程序,希望您能在 WebGrid 中看到所有客户,如下所示:
添加内联编辑操作
要编辑任何客户,我们将使用 WebGrid 中的内联编辑。正如您在 WebGrid 的第四列中看到的,我们使用图像 - 一个用于编辑,另一个用于删除操作。
在本节中,我们将编写一些代码,以便在单击编辑图像时,相应行中的数据可以进行编辑。同时,编辑图像将出现在相同位置,并显示保存图像和适当的工具提示。因此,编辑功能如下所示:
单击保存图像时,编辑后的客户对象将进入 CustomerController 的 EditCustomer Action 方法。然后该 Action 方法将调用 WCF 服务,服务将使用存储库将更新后的客户保存在数据库中。
从编程角度来看,WebGrid 中的每一行都有一个 span 标签和一个带有不同 CSS 类的 input 标签。页面加载时,所有带有 CSS 类“edit-mode”的文本框都将隐藏。我们还考虑到一次应该只有一个行可编辑。为了实现内联编辑,我们在单击编辑按钮时切换 CSS 类,因为现在 span 标签应该被隐藏,而文本框应该出现在相应的行中。
如果编辑功能还不清楚,请运行应用程序并查看编辑按钮的行为,然后查看 index.js 文件中编写的 JavaScript 代码。或者,您可以继续按照以下步骤操作,随着代码的输入和理解,事情会变得显而易见。
- 打开 Scripts 文件夹下的 index.js 文件,并写入以下代码。此代码会在页面加载时隐藏不需要在查看模式下使用的输入框(带有 CSS 类“edit-mode”)。
$(document).ready(function () { $('.edit-mode').hide(); });
- 此外,我们需要编写 JavaScript 来处理单击编辑按钮的事件。在 index.js 中写入以下代码。希望代码中的注释足以解释它。
$('.edit-button').on("click", function () { // allEditableRow : will have all rows which are editable (where save button is visible). var allEditableRow = $("[src='/Content/images/save.jpg']"); // make row editable only if no other row is editable as of now by toggle // otherwise go to else and save data of editable row first or alert to save that" if (allEditableRow.length == 0) { var tr = $(this).parents('tr:first'); tr.find('.edit-mode,.display-mode').toggle(); var imageSource = $(this).attr('src'); if (imageSource == '/Content/images/edit.jpg') { $(this).attr('src', '/Content/images/save.jpg'); $(this).attr('title', 'Save Customer'); } } else { // making sure that only one row is editable and save button of editable row is clicked if (allEditableRow.length == 1 && $(this).attr('src') == '/Content/images/save.jpg') { var selectedId = $(this).parents('tr').find('td:nth-child(1)').text().trim(); var selectedName = $(this).parents('tr').find('#CustomerName').val(); var selectedAddless = $(this).parents('tr').find('#CustomerAddress').val(); // create object with updated values var customerModel = { "CustomerId": selectedId, "CustomerName": selectedName, "CustomerAddress": selectedAddless }; $.ajax({ url: '/Customer/EditCustomer', type: 'POST', contentType: 'application/json; charset=utf-8', data: JSON.stringify(customerModel) }); alert("Your data is saved"); window.location.reload(true); $(this).attr('src', '/Content/images/edit.jpg'); } else { alert("Please finish the editing of current editable row. Save first"); } }
- 在 CustomerController 中,我们需要实现 EditCustomer Action 方法,如下所示:
public void EditCustomer(Customer customer) { using (WebClient wc = new WebClient()) { MemoryStream ms = new MemoryStream(); DataContractJsonSerializer serializerToUplaod = new DataContractJsonSerializer(typeof(Customer)); serializerToUplaod.WriteObject(ms, customer); wc.Headers["Content-type"] = "application/json"; wc.UploadData(customerServiceUri + "EditCustomer", "PUT", ms.ToArray()); } }
- 运行应用程序,编辑任何客户,然后保存它,更新的数据将保存在数据库中,并在 WebGrid 中反映出来。
添加内联删除操作
要删除记录,用户将单击相应行中的删除图像。用户将收到一个确认弹出窗口。如果用户确认删除,则相应的行数据将被删除。删除按钮单击时的确认弹出窗口如下屏幕截图所示。
我们将编写删除功能的代码。
- 打开 Scripts 文件夹下的 index.js 文件,并写入以下代码:
$('.delete-customer').click(function () { var selectedId = $(this).parents('tr').find('td:nth-child(1)').text().trim(); var selectedName = $(this).parents('tr').find('#CustomerName').val(); var message = "Please confirm delete for Customer ID " + selectedId + ", and Name: " + selectedName + " ? \nClick 'OK' to delete otherwise 'Cancel'."; if (confirm(message) == true) { selectedId = $(this).parents('tr:first').children('td:first').text(); $.ajax({ url: '/Customer/DeleteCustomer', data: { id: selectedId }, type: 'POST', success: function () { window.location.reload(); }, error: function (xhr) { alert("something seems wrong"); } }); } else { alert("Delete is Canceled!"); } });
- 在 CustomerController 类中写入以下代码。此 Action 方法将用于删除操作。
public void DeleteCustomer(int id) { using (WebClient wc = new WebClient()) { MemoryStream ms = new MemoryStream(); DataContractJsonSerializer serializerToUplaod = new DataContractJsonSerializer(typeof(Customer)); serializerToUplaod.WriteObject(ms, id); wc.Headers["Content-type"] = "application/json"; wc.UploadData(customerServiceUri + "DeleteCustomer", "DELETE", ms.ToArray()); } }
- 运行应用程序,尝试从 WebGrid 中删除任何记录,它应该按预期工作。
添加创建操作
为了实现此功能,我们将使用部分视图。当用户单击“新建客户”按钮时,AJAX 调用会转到 CustomerController 的 GetCustomerPV Action 方法,并获取部分视图。将出现一个表单,用户将填写数据并单击表单内的“保存”按钮。然后调用将转到 CustomerController 的 CreateCustomer Action 方法来保存新客户。我们在此处没有使用广泛的验证,但两个字段都是必填项。如果单击保存按钮而不填写任何数据,则会显示错误消息,如下面的屏幕截图所示。
让我们按照以下步骤来实现此功能:
- 在 CustomerController 中写入以下代码行:
public ActionResult GetCustomerPV() { return PartialView("CreateCustomerPV"); }
- 通过右键单击 GetCustomerPV Action 方法并将其命名为 CreateCustomerPV 来创建一个部分视图。打开新创建的 CreateCustomerPV 部分视图并写入以下代码:
@model DemoMVCWebApp.Models.Customer @*Below scripts files are used to provide the client side validation*@ <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.js"></script> <div class="createDiv"> <h4>Please fill below Customer Form:</h4> <br /> @using (Html.BeginForm("CreateCustomer", "Customer")) { @Html.AntiForgeryToken() <div class="form-horizontal"> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(model => model.CustomerName, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.CustomerName) @Html.ValidationMessageFor(model => model.CustomerName) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.CustomerAddress, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.CustomerAddress) @Html.ValidationMessageFor(model => model.CustomerAddress) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Save" class="btnCustomerPV" /> </div> </div> </div> } </div>
- 现在,我们需要在主页面上添加一个名为“新建客户”的按钮,单击该按钮将调用部分视图。在 Index.cshtml 文件(Index 视图)中,将以下代码添加到 div 标签的正下方。我们添加了一个“div”标签,部分视图将添加到其中。
<input type="button" value="New Customer" class="btnCustomerPV" /> <div id="placeHolderCustomerPV"> </div>
现在打开 index.js 文件,并添加以下代码行,这将调用 GetCustomerPV Action 方法:$('.btnCustomerPV').click(function () { $('.btnCustomerPV').hide(); $.ajax({ // Call CreatePartialView action method url: '/Customer/GetCustomerPV', type: 'Get', success: function (data) { $("#placeHolderCustomerPV").empty().append(data); }, error: function () { alert("something seems wrong"); } }); });
- 我们在部分视图中编写了以下代码,因此在单击部分视图的提交按钮时,调用将进入 CustomerController 的 CreateCustomer Action 方法。
@using (Html.BeginForm("CreateCustomer", "Customer"))
在控制器中写入以下代码行以添加 CreateCustomer Action 方法:public ActionResult CreateCustomer(Customer customer) { using (WebClient wc = new WebClient()) { MemoryStream ms = new MemoryStream(); DataContractJsonSerializer serializerToUplaod = new DataContractJsonSerializer(typeof(Customer)); serializerToUplaod.WriteObject(ms, customer); wc.Headers["Content-type"] = "application/json"; wc.UploadData(customerServiceUri + "AddCustomer", "POST", ms.ToArray()); } int pageToShow; int totalCustomers; List<Customer> customerList = new List<Customer>(); using (WebClient webClient = new WebClient()) { string customerCount; customerCount = webClient.DownloadString(customerServiceUri + "GetCustomersCount"); totalCustomers = Convert.ToInt32(customerCount); } if (totalCustomers % 5 != 0) pageToShow = (totalCustomers / 5) + 1; else pageToShow = totalCustomers / 5; return Redirect(HttpRuntime.AppDomainAppVirtualPath + "?page=" + pageToShow); }
在此,在保存新客户后,我们将重定向到适当的索引以显示最近添加的数据。
- 现在运行应用程序,单击“新建客户”按钮,在表单中填写数据,然后单击“保存”按钮。数据将被保存,并且由于我们编写了重定向逻辑,它将显示在 WebGrid 控件的最后一行。
结论
希望您已享受我们在两篇文章中创建的演示,并学习了如何创建 WCF RESTful 服务及其在 ASP.NET MVC 应用程序中使用 WebGrid 控件的消耗。您的评论和建议非常欢迎。谢谢。