第 3 部分:创建管理员控制器
作者:Rick Anderson
添加管理员控制器
在本部分中,我们将添加一个 Web API 控制器,该控制器支持 CRUD (对产品执行创建、读取、更新和删除) 操作。 控制器将使用 Entity Framework 与数据库层通信。 只有管理员才能使用此控制器。 客户将通过另一个控制器访问产品。
在“解决方案资源管理器”中,右键单击“控制器”文件夹。 选择 “添加” ,然后选择“ 控制器”。
在“ 添加控制器 ”对话框中,将控制器 AdminController
命名为 。 在 “模板”下,选择“使用实体框架执行读/写操作的 API 控制器”。 在 “模型类”下,选择“Product (ProductStore.Models) ”。 在 “数据上下文”下,选择“<新建数据上下文>”。
注意
如果 “模型类 ”下拉列表未显示任何模型类,请确保已编译项目。 实体框架使用反射,因此它需要编译的程序集。
选择“<新建数据上下文>”将打开“ 新建数据上下文 ”对话框。 将数据上下文 ProductStore.Models.OrdersContext
命名为 。
单击“ 确定 ”关闭“ 新建数据上下文 ”对话框。 在“ 添加控制器 ”对话框中,单击“ 添加”。
下面是添加到项目的内容:
- 从 DbContext 派生的名为
OrdersContext
的类。 此类提供 POCO 模型与数据库之间的粘附。 - 名为 的
AdminController
Web API 控制器。 此控制器支持对实例执行Product
CRUD 操作。 它使用OrdersContext
类与 Entity Framework 通信。 - Web.config 文件中的新数据库连接字符串。
打开 OrdersContext.cs 文件。 请注意,构造函数指定数据库连接字符串的名称。 此名称是指添加到Web.config的连接字符串。
public OrdersContext() : base("name=OrdersContext")
向 OrdersContext
类添加以下属性:
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
DbSet 表示一组可以查询的实体。 下面是 类的完整列表 OrdersContext
:
public class OrdersContext : DbContext
{
public OrdersContext() : base("name=OrdersContext")
{
}
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Product> Products { get; set; }
}
类 AdminController
定义了实现基本 CRUD 功能的五种方法。 每个方法对应于客户端可以调用的 URI:
控制器方法 | 描述 | URI | HTTP 方法 |
---|---|---|---|
GetProducts | 获取所有产品。 | api/products | GET |
GetProduct | 按 ID 查找产品。 | api/products/id | GET |
PutProduct | 汇报产品。 | api/products/id | PUT |
PostProduct | 创建新产品。 | api/products | POST |
DeleteProduct | 删除产品。 | api/products/id | DELETE |
每个方法调用 以 OrdersContext
查询数据库。 修改集合的方法 (PUT、POST 和 DELETE) 调用 db.SaveChanges
,以保留对数据库的更改。 控制器按 HTTP 请求创建,然后释放,因此有必要在方法返回之前保留更改。
添加数据库初始值设定项
实体框架有一个很好的功能,可用于在启动时填充数据库,并在模型更改时自动重新创建数据库。 此功能在开发过程中很有用,因为即使更改了模型,也始终具有一些测试数据。
在解决方案资源管理器中,右键单击 Models 文件夹并创建名为 OrdersContextInitializer
的新类。 粘贴以下实现:
namespace ProductStore.Models
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
public class OrdersContextInitializer : DropCreateDatabaseIfModelChanges<OrdersContext>
{
protected override void Seed(OrdersContext context)
{
var products = new List<Product>()
{
new Product() { Name = "Tomato Soup", Price = 1.39M, ActualCost = .99M },
new Product() { Name = "Hammer", Price = 16.99M, ActualCost = 10 },
new Product() { Name = "Yo yo", Price = 6.99M, ActualCost = 2.05M }
};
products.ForEach(p => context.Products.Add(p));
context.SaveChanges();
var order = new Order() { Customer = "Bob" };
var od = new List<OrderDetail>()
{
new OrderDetail() { Product = products[0], Quantity = 2, Order = order},
new OrderDetail() { Product = products[1], Quantity = 4, Order = order }
};
context.Orders.Add(order);
od.ForEach(o => context.OrderDetails.Add(o));
context.SaveChanges();
}
}
}
通过继承自 DropCreateDatabaseIfModelChanges 类,我们告诉 Entity Framework 在修改模型类时删除数据库。 当实体框架创建 (或重新创建) 数据库时,它会调用 Seed 方法来填充表。 我们使用 Seed 方法添加一些示例产品以及一个示例订单。
此功能非常适合测试,但不要在生产环境中使用 DropCreateDatabaseIfModelChanges 类,因为如果有人更改模型类,可能会丢失数据。
接下来,打开 Global.asax 并将以下代码添加到 Application_Start 方法:
System.Data.Entity.Database.SetInitializer(
new ProductStore.Models.OrdersContextInitializer());
向控制器发送请求
目前,我们尚未编写任何客户端代码,但你可以使用 Web 浏览器或 HTTP 调试工具(如 Fiddler)调用 Web API。 在 Visual Studio 中,按 F5 开始调试。 Web 浏览器将打开 , http://localhost:*portnum*/
其中 portnum 是某个端口号。
将 HTTP 请求发送到 “http://localhost:*portnum*/api/admin
. 第一个请求的完成速度可能很慢,因为实体框架需要创建数据库并设定其种子。 响应应类似于以下内容:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 18 Jun 2012 04:30:33 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Content-Length: 175
Connection: Close
[{"Id":1,"Name":"Tomato Soup","Price":1.39,"ActualCost":0.99},{"Id":2,"Name":"Hammer",
"Price":16.99,"ActualCost":10.00},{"Id":3,"Name":"Yo yo","Price":6.99,"ActualCost":
2.05}]