二、ASP.NET Web API 2 进阶之增删改查

本次教程演示怎样使用 ASP.NET Web API HTTP 服务来进行增删改查。

增删改查的英文所系额为CRUD,即"创建(Create)、 读取(Read)、 更新(Update)和删除(Delete),"这是四个基本的数据库操作。

现在,很多HTTP服务都通过REST(Representational State Transfer表述性状态转移)来模拟增删改查操作。

在本次教程中,我们将会创建非常简单的 web API 来管理产品的列表。每个产品将包含名称、 价格、类别 (如"玩具"或"硬件")和一个产品 id。

Product API 将公开以下几个接口

行动HTTP 方法相对 URI
获取所有产品的列表 GET /api/products
根据 ID 获取产品 GET /api/products/id
把一个产品类别 GET /api/products?category=category
创建一个新的产品 POST /api/products
产品更新 PUT /api/products/id
删除产品 DELETE /api/products/id

注意:某些 Uri 路径中包括产品 ID。例如,若要获取 ID 是 28 的产品,客户端发送一个 GET 请求为http://主机名/api/products/28.

资源

Product API 为两个资源类型定义 的Uri:

资源URI
所有产品的列表。 /api/products
个别产品。 /api/products/id

方法

四个主要的 HTTP 方法(GET、PUT、POST 和 DELETE)可以映射到以下的 CRUD 操作:

  • GET 操作将检索在指定的 URI 的资源的表示形式。获取应在服务器上有没有副作用。
  • PUT 将更新在指定 URI 处的资源。放也被用于在指定的 URI,创建一个新的资源如果服务器允许客户端指定新的 Uri。对于本教程,该 API 将不支持通过投入创作。
  • POST 将创建一个新的资源。服务器分配新对象的 URI,并返回此 URI 作为响应消息的一部分。
  • DELETE 将删除在指定 URI 处的资源。

注: 中的 PUT 方法将替换整个产品实体。也就是说,客户端预计发送更新的产品的完整表示。如果您想要支持部分更新、 修补程序方法是首选。本教程不实现修补程序。

创建一个新的 Web API 项目

通过运行 Visual Studio 启动并从起始页选择新的项目或者,从文件菜单中,选择新建,然后项目.

模板窗格中,选择已安装的模板和展开Visual C#节点。Visual C#中,选择Web在项目模板的列表中,选择ASP.NET MVC 4 Web 应用程序名称"ProductStore"项目,然后单击确定.

新的 ASP.NET MVC 4 项目对话框中,选择Web API并单击确定.

添加模型

模型是一个对象,表示您的应用程序中的数据。在 ASP.NET Web API,你可以使用强类型的 CLR 对象作为模型,和他们将自动被序列化到 XML 或 JSON,该客户端。

对于 ProductStore API,由我们的数据组成的产品,因此我们创建了一个名为Product的新类.

如果解决方案资源管理器已不可见,请单击视图菜单,然后选择解决方案资源管理器在解决方案资源管理器中,右键单击模型文件夹。从上下文繁体,选择添加,然后选择命名类"Product"。

将以下属性添加到Product类。

namespaceProductStore.Models{publicclassProduct{publicintId{get;set;}publicstringName{get;set;}publicstringCategory{get;set;}publicdecimalPrice{get;set;}}}

添加一个存储库

我们需要存储的产品的集合。它是个好主意要分开收集从我们的服务实现。这样,我们可以改变后备存储,无需改写的服务类。这种类型的设计称为存储库模式。首先定义一个泛型接口存储库中。

在解决方案资源管理器中,右键单击模型文件夹。选择添加,然后选择新的项目.

模板窗格中,选择已安装的模板和展开的节点 C#。在 C# 中,选择的代码在代码模板的列表中,选择的接口"IProductRepository"的接口的名称。

添加下面的实现:

namespaceProductStore.Models{publicinterfaceIProductRepository{IEnumerable<Product>GetAll();ProductGet(int id);ProductAdd(Product item);voidRemove(int id);boolUpdate(Product item);}}

现在将另一个类添加到模型文件夹,命名为"ProductRepository"。此类将实现IProductRespository接口。添加下面的实现:

namespaceProductStore.Models{publicclassProductRepository:IProductRepository{privateList<Product> products =newList<Product>();privateint _nextId =1;publicProductRepository(){Add(newProduct{Name="Tomato soup",Category="Groceries",Price=1.39M});Add(newProduct{Name="Yo-yo",Category="Toys",Price=3.75M});Add(newProduct{Name="Hammer",Category="Hardware",Price=16.99M});}publicIEnumerable<Product>GetAll(){return products;}publicProductGet(int id){return products.Find(p => p.Id== id);}publicProductAdd(Product item){if(item ==null){thrownewArgumentNullException("item");}
            item.Id= _nextId++;
            products.Add(item);return item;}publicvoidRemove(int id){
            products.RemoveAll(p => p.Id== id);}publicboolUpdate(Product item){if(item ==null){thrownewArgumentNullException("item");}int index = products.FindIndex(p => p.Id== item.Id);if(index ==-1){returnfalse;}
            products.RemoveAt(index);
            products.Add(item);returntrue;}}}

存储库中保持在本地内存中的列表。这是确定的教程,但在实际的应用中,您将存储的数据在外部,任一数据库或在云存储中。存储库模式将使易于更改以后实施。

添加 Web API 控制器

如果您使用过 ASP.NET MVC,那么应该已经熟悉控制器了。在 ASP.NET Web API 中,控制器是一个类,处理来自客户端的 HTTP 请求。新项目向导创建为你的两个控制器,它在创建项目时。若要看到他们,展开在解决方案资源管理器中的控制器文件夹。

  • HomeController 是一个传统的 ASP.NET MVC 控制器。它是负责服务站点的 HTML 页,并没有直接关系到我们的 web API。
  • ValuesController 是一种示例 WebAPI 控制器。

去和通过右键单击解决方案资源管理器中的文件并选择删除 ValuesController,删除。现在添加一个新的控制器,如下:

解决方案资源管理器中,右键单击控制器文件夹。选择添加,然后选择控制器.

添加控制器向导中,将控制器命名为“ProductsController”。模板下拉列表中选择空的 API 控制器然后单击添加.

没有必要将您的控制器放入一个命名为 Controllers 的文件夹。文件夹的名称并不重要 ;这是组织您的源文件的一种简单方法。

添加控制器向导将在 Controllers 文件夹中创建一个名为 ProductsController.cs 的文件。如果该文件尚未打开,请双击该文件以将其打开。添加以下使用语句:

usingProductStore.Models;

添加一个包含IProductRepository实例的字段。

publicclassProductsController:ApiController{staticreadonlyIProductRepository repository =newProductRepository();}

在控制器中调用new ProductRepository()不是最好的设计,因为它关系到特定的实现的IProductRepository控制器。更好的方法,请参阅使用 Web API 依赖关系解析程序.

获取资源

ProductStore API 将作为 HTTP GET 方法公开几个"读"操作。每个操作将对应于ProductsController类中的方法。

行动HTTP 方法相对 URI
获取所有产品的列表 GET /api/products
根据 ID 获取产品 GET /api/products/id
把一个产品类别 GET /api/products?category=category

要获取所有产品的列表,请将此方法添加到ProductsController类:

publicclassProductsController:ApiController{publicIEnumerable<Product>GetAllProducts(){return repository.GetAll();}// ....}

方法名称启动以"Get",所以由公约 》 它映射到 GET 请求。此外,因为该方法没有参数,它映射到一个不包含在路径中的"id"线段的 URI。

若要获取产品的 ID,请将此方法添加到ProductsController类:

publicProductGetProduct(int id){Product item = repository.Get(id);if(item ==null){thrownewHttpResponseException(HttpStatusCode.NotFound);}return item;}

此方法名称也开始以"Get",但该方法具有名为id的参数。此参数映射到的 URI 路径的"id"部分。ASP.NET Web API 框架会自动将 ID 转换为正确的数据类型 (int) 的参数。

如果id不是有效的 GetProduct 方法将引发异常类型HttpResponseException 。此异常将由框架变成一个 404 (未找到) 错误。

最后,添加一个方法,按类别查找产品:

publicIEnumerable<Product>GetProductsByCategory(string category){return repository.GetAll().Where(
        p =>string.Equals(p.Category, category,StringComparison.OrdinalIgnoreCase));}

如果请求的 URI 的查询字符串,Web API 会尝试匹配上的控制器方法的参数的查询参数。因此,窗体“api/products?category=category”的 URI 将映射到此方法。

创建资源

下一步,我们会将方法添加到ProductsController类,以创建一种新产品。下面是一个简单的方法实现:

// Not the final implementation!publicProductPostProduct(Product item){
    item = repository.Add(item);return item;}

请注意有关此方法的两件事:

  • 方法名称以“Post...”开头。若要创建一个新的产品,客户端发送一个 HTTP POST 请求。
  • 该方法采用类型为 Product 的参数。在 Web API 中,具有复杂类型的参数是从请求正文的反序列化得来的。因此,我们期望客户端发送 XML 或 JSON 格式的一个产品对象的序列化表示形式。

此实现会工作,但它还很不完整。理想情况下,我们希望的 HTTP 响应,包括以下内容:

  • 响应代码:默认情况下,Web API 框架将响应状态代码设置为 200 (OK)。但根据 HTTP/1.1 协议中,当 POST 请求的结果在创造一种资源,服务器应该回复状态为 201 (已创建)。
  • 位置:当服务器创建一个资源时,它应在响应的 Location 标头中包含新资源的 URI。

ASP.NET Web API 使得容易操纵的 HTTP 响应消息。下面是改进的执行:

publicHttpResponseMessagePostProduct(Product item){
    item = repository.Add(item);var response =Request.CreateResponse<Product>(HttpStatusCode.Created, item);string uri =Url.Link("DefaultApi",new{ id = item.Id});
    response.Headers.Location=newUri(uri);return response;}

请注意此方法返回类型现在是HttpResponseMessage通过返回HttpResponseMessage而不是产品,我们可以控制的 HTTP 响应消息,包括状态代码和位置标头的详细信息。

CreateResponse 方法将会创建 HttpResponseMessage,并自动将 Product 对象的序列化表示形式写入到响应消息的正文中。

此示例不会验证该Product模型验证有关的信息,请参见ASP.NET Web API 中的模型验证.

更新资源

使用 PUT 更新产品非常简单:

publicvoidPutProduct(int id,Product product){
    product.Id= id;if(!repository.Update(product)){thrownewHttpResponseException(HttpStatusCode.NotFound);}}

方法名称以“Put...”开头,这样 Web API 就能够将其与 PUT 请求相匹配。该方法采用两个参数、 产品 ID 和更新的产品。Id 参数是从 URI 路径获得的,而 product 参数则是从请求正文的反序列化得来的。默认情况下,ASP.NET Web API 框架从路由获取简单的参数类型,从请求正文获取复杂的类型。

删除资源

若要删除资源,请定义一个“Delete...”方法。

publicvoidDeleteProduct(int id){Product item = repository.Get(id);if(item ==null){thrownewHttpResponseException(HttpStatusCode.NotFound);}

        repository.Remove(id);}

如果删除请求成功,它可以返回状态 200 (OK) 与实体的描述该状态 ;如果删除仍然挂起,则返回状态 202 (已接受);或状态与没有实体正文 204 (无内容)。在这种情况下, DeleteProduct方法具有void返回类型,因此 ASP.NET Web API 自动转换此状态代码 204 (无内容)。

posted @ 2014-05-06 11:26  SimpleCoder  阅读(473)  评论(0编辑  收藏  举报