作者: Tom FitzMacken
本教程系列演示了将模型绑定与 ASP.NET Web 窗体项目配合使用的基本方面。 模型绑定使数据交互比处理数据源对象(如 ObjectDataSource 或 SqlDataSource)更加简单直接。 本系列从介绍性材料开始,并在后续教程中转到更高级的概念。
本教程演示如何将模型绑定与业务逻辑层配合使用。 将 OnCallingDataMethods 成员设置为指定使用当前页以外的对象来调用数据方法。
本教程基于在该系列较早部分创建的项目。
可以在 C# 或 VB 中 下载 完整的项目。 可下载的代码适用于 Visual Studio 2012 或 Visual Studio 2013。 它使用 Visual Studio 2012 模板,与本教程中显示的 Visual Studio 2013 模板略有不同。
您将构建的内容
通过模型绑定,可以将数据交互代码放入网页的代码隐藏文件中或单独的业务逻辑类中。 前面的教程演示了如何使用后台代码文件进行数据交互。 此方法适用于小型网站,但在维护大型站点时可能会导致代码重复和难度更大。 也很难以编程方式测试驻留在文件背后的代码中的代码,因为没有抽象层。
若要集中数据交互代码,可以创建一个业务逻辑层,其中包含用于与数据交互的所有逻辑。 然后,从网页调用业务逻辑层。 本教程演示如何将前面教程中编写的所有代码移动到业务逻辑层,然后从页面中使用该代码。
在本教程中,你将:
- 将代码从后台代码文件移动到业务逻辑层
- 更改数据绑定控件以调用业务逻辑层中的方法
创建业务逻辑层
现在,你将创建从网页调用的类。 此类中的方法类似于在前面的教程中使用的方法,并包括值提供程序属性。
首先,添加名为 BLL 的新文件夹。
在 BLL 文件夹中,创建名为 SchoolBL.cs的新类。 它将包含最初驻留在后台代码文件中的所有数据操作。 这些方法几乎与代码隐藏文件中的方法相同,但将包含一些更改。
要注意的最重要更改是,不再从 Page 类的实例中执行代码。 Page 类包含 TryUpdateModel 方法和 ModelState 属性。 将此代码移动到业务逻辑层时,不再有 Page 类的实例来调用这些成员。 若要解决此问题,必须将 ModelMethodContext 参数添加到访问 TryUpdateModel 或 ModelState 的任何方法。 使用此 ModelMethodContext 参数调用 TryUpdateModel 或检索 ModelState。 无需更改网页中的任何内容即可考虑此新参数。
将SchoolBL.cs中的代码替换为以下代码。
using System;
using System.Linq;
using ContosoUniversityModelBinding.Models;
using System.Web.ModelBinding;
using System.Web.UI.WebControls;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
namespace ContosoUniversityModelBinding.BLL
{
public class SchoolBL : IDisposable
{
SchoolContext db = new SchoolContext();
public IQueryable<Student> GetStudents([Control] AcademicYear? displayYear)
{
var query = db.Students.Include(s => s.Enrollments.Select(e => e.Course));
if (displayYear != null)
{
query = query.Where(s => s.Year == displayYear);
}
return query;
}
public void InsertStudent(ModelMethodContext context)
{
var item = new Student();
context.TryUpdateModel(item);
if (context.ModelState.IsValid)
{
db.Students.Add(item);
db.SaveChanges();
}
}
public void DeleteStudent(int studentID, ModelMethodContext context)
{
var item = new Student { StudentID = studentID };
db.Entry(item).State = EntityState.Deleted;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
context.ModelState.AddModelError("",
String.Format("Item with id {0} no longer exists in the database.", studentID));
}
}
public void UpdateStudent(int studentID, ModelMethodContext context)
{
Student item = null;
item = db.Students.Find(studentID);
if (item == null)
{
context.ModelState.AddModelError("", String.Format("Item with id {0} was not found", studentID));
return;
}
context.TryUpdateModel(item);
if (context.ModelState.IsValid)
{
db.SaveChanges();
}
}
public IQueryable<Enrollment> GetCourses([QueryString] int? studentID)
{
var query = db.Enrollments.Include(e => e.Course)
.Where(e => e.StudentID == studentID);
return query;
}
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
db.Dispose();
}
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
修改现有页面以从业务逻辑层检索数据
最后,你将将页面Students.aspx、AddStudent.aspx和Courses.aspx从使用代码隐藏文件中的查询转换为使用业务逻辑层。
在 Students、AddStudent 和 Courses 的代码隐藏文件中,删除或注释掉以下查询方法:
- studentsGrid_GetData
- 学生网格_更新项目
- studentsGrid_DeleteItem
- 添加学生表单_插入项
- coursesGrid_GetData
现在,后置代码文件中不应包含与数据操作相关的代码。
OnCallingDataMethods 事件处理程序使你可以指定要用于数据方法的对象。 在 Students.aspx 中,为该事件处理程序添加一个值,并将数据方法的名称更改为业务逻辑类中方法的名称。
<asp:GridView runat="server" ID="studentsGrid"
ItemType="ContosoUniversityModelBinding.Models.Student" DataKeyNames="StudentID"
SelectMethod="GetStudents"
UpdateMethod="UpdateStudent" DeleteMethod="DeleteStudent"
AllowSorting="true" AllowPaging="true" PageSize="4"
AutoGenerateEditButton="true" AutoGenerateDeleteButton="true"
AutoGenerateColumns="false"
OnCallingDataMethods="studentsGrid_CallingDataMethods">
在Students.aspx的代码隐藏文件中,为 CallingDataMethods 事件定义事件处理程序。 在此事件处理程序中,指定数据操作的业务逻辑类。
protected void studentsGrid_CallingDataMethods(object sender, CallingDataMethodsEventArgs e)
{
e.DataMethodsObject = new ContosoUniversityModelBinding.BLL.SchoolBL();
}
在AddStudent.aspx中,进行类似的更改。
<asp:FormView runat="server" ID="addStudentForm"
ItemType="ContosoUniversityModelBinding.Models.Student"
InsertMethod="InsertStudent" DefaultMode="Insert"
OnCallingDataMethods="addStudentForm_CallingDataMethods"
RenderOuterTable="false" OnItemInserted="addStudentForm_ItemInserted">
protected void addStudentForm_CallingDataMethods(object sender, CallingDataMethodsEventArgs e)
{
e.DataMethodsObject = new ContosoUniversityModelBinding.BLL.SchoolBL();
}
在Courses.aspx中,进行类似的更改。
<asp:GridView runat="server" ID="coursesGrid"
ItemType="ContosoUniversityModelBinding.Models.Enrollment"
SelectMethod="GetCourses" AutoGenerateColumns="false"
OnCallingDataMethods="coursesGrid_CallingDataMethods">
protected void coursesGrid_CallingDataMethods(object sender, CallingDataMethodsEventArgs e)
{
e.DataMethodsObject = new ContosoUniversityModelBinding.BLL.SchoolBL();
}
运行应用程序,并注意到所有页面都像以前一样运行。 验证逻辑也正常工作。
结束语
在本教程中,你将重新构建应用程序以使用数据访问层和业务逻辑层。 你指定数据控件使用的对象不是数据操作的当前页。