【ASP.NET Web API教程】2.3.6 创建产品和订单控制器

简介: 原文:【ASP.NET Web API教程】2.3.6 创建产品和订单控制器注:本文是【ASP.NET Web API系列教程】的一部分,如果您是第一次看本博客文章,请先看前面的内容。 Part 6: Creating Product and Order Controllers 第6部分:创建产品和订单控制器 本文引自:http://www.
原文: 【ASP.NET Web API教程】2.3.6 创建产品和订单控制器

注:本文是【ASP.NET Web API系列教程】的一部分,如果您是第一次看本博客文章,请先看前面的内容。

Part 6: Creating Product and Order Controllers
第6部分:创建产品和订单控制器

本文引自:http://www.asp.net/web-api/overview/creating-web-apis/using-web-api-with-entity-framework/using-web-api-with-entity-framework,-part-6

Add a Products Controller
添加产品控制器

The Admin controller is for users who have administrator privileges. Customers, on the other hand, can view products but cannot create, update, or delete them.
Admin控制器是用于具有管理员权限的用户的。另一方面,一般客户可以查看产品,但不能创建、更新或删除。

We can easily restrict access to the Post, Put, and Delete methods, while leaving the Get methods open. But look at the data that is returned for a product:
我们可以很容易地对Post、Put和Delete方法进行限制访问,而只让Get方法是开放的。但先看一看针对一个产品所返回的数据:

{"Id":1,"Name":"Tomato Soup","Price":1.39,"ActualCost":0.99}

The ActualCost property should not be visible to customers! The solution is to define a data transfer object (DTO) that includes a subset of properties that should be visible to customers. We will use LINQ to project Product instances to ProductDTO instances.
ActualCost(实际开销,指该产品的成本 — 译者注)属性不应该是客户可见的。其解决方案是定义包含属性子集的、客户可见的一个data transfer object(DTO — 数据传输对象)。我们将用LINQ把Product实例投影到ProductDTO实例。

Add a class named ProductDTO to the Models folder.
添加一个名称为ProductDTO的类到Models文件夹:

namespace ProductStore.Models 
{ 
    public class ProductDTO 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 
        public decimal Price { get; set; } 
    } 
}

Now add the controller. In Solution Explorer, right-click the Controllers folder. Select Add, then select Controller. In the Add Controller dialog, name the controller "ProductsController". Under Template, select Empty API controller.
现在添加控制器。在“解决方案资源管理器”中右击Controllers文件夹。选择“添加”,然后选择“控制器”。在“添加控制器”对话框中,将此控制器命名为“ProductsController”。在“模板”的下面选择“空的API控制器”(见图2-24)。

WebAPI2-24

图2-24. 添加ProductsController控制器

Replace everything in the source file with the following code:
用以下代码替换源文件的全部内容:

namespace ProductStore.Controllers 
{ 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Net; 
    using System.Net.Http; 
    using System.Web.Http; 
    using ProductStore.Models; 
public class ProductsController : ApiController { private OrdersContext db = new OrdersContext();
// Project products to product DTOs. // 把products投影到product DTOs private IQueryable<ProductDTO> MapProducts() { return from p in db.Products select new ProductDTO() { Id = p.Id, Name = p.Name, Price = p.Price }; }
public IEnumerable<ProductDTO> GetProducts() { return MapProducts().AsEnumerable(); }
public ProductDTO GetProduct(int id) { var product = (from p in MapProducts() where p.Id == 1 select p).FirstOrDefault(); if (product == null) { throw new HttpResponseException( Request.CreateResponse(HttpStatusCode.NotFound)); } return product; }
protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); } } }

The controller still uses the OrdersContext to query the database. But instead of returning Product instances directly, we call MapProducts to project them onto ProductDTO instances:
该控制器仍然使用了OrdersContext去查询数据库,但并不是直接返回Product实例,而是调用MapProducts把它们投影到ProductDTO实例:

return from p in db.Products select new ProductDTO()
    { Id = p.Id, Name = p.Name, Price = p.Price };

The MapProducts method returns an IQueryable, so we can compose the result with other query parameters. You can see this in the GetProduct method, which adds a where clause to the query:
MapProducts方法会返回一个IQueryable,因此我们可以用其它查询参数来构造结果。你可以在GetProduct方法中看到这一做法,它对查询添加了一个where子句:

var product = (from p in MapProducts()
    where p.Id == 1
    select p).FirstOrDefault();

Add an Orders Controller
添加订单控制器

Next, add a controller that lets users create and view orders.
下一步,添加一个让用户创建并查看订单的控制器。

We'll start with another DTO. In Solution Explorer, right-click the Models folder and add a class named OrderDTO. Use the following implementation:
创建另一个DTO。在“解决方案资源管理器”中,右击Models文件夹,并添加一个名称为OrderDTO的类。使用以下实现:

namespace ProductStore.Models 
{ 
    using System.Collections.Generic;
public class OrderDTO { public class Detail { public int ProductID { get; set; } public string Product { get; set; } public decimal Price { get; set; } public int Quantity { get; set; } } public IEnumerable<Detail> Details { get; set; } } }

Now add the controller. In Solution Explorer, right-click the Controllers folder. Select Add, then select Controller. In the Add Controller dialog, set the following options:
现在,添加控制器。在“解决方案资源管理器”中,右击Controllers文件夹。选择“添加”,然后选择“控制器”。在“添加控制器”对话框中,设置以下选项:

  • Under Controller Name, enter "OrdersController".
    在“控制器名称”下输入“OrdersController”。
  • Under Template, select “API controller with read/write actions, using Entity Framework”.
    在“模板”下选择“API controller with read/write actions, using Entity Framework(使用实体框架的、带有读/写动作的API控制器)”。
  • Under Model class, select "Order (ProductStore.Models)".
    在“模型类”下选择“Order (ProductStore.Models)”。
  • Under Data context class, select "OrdersContext (ProductStore.Models)".
    在“数据上下文类”下选择“OrdersContext (ProductStore.Models)”。

以上选项设置如图2-25所示。

WebAPI2-25

图2-25. OrdersController控制器设置

Click Add. This adds a file named OrdersController.cs. Next, we need to modify the default implementation of the controller.
点击“添加”。这会添加一个名称为OrdersController.cs的文件。下一步,我们需要修改该控制器的默认实现。

First, delete the PutOrder and DeleteOrder methods. For this sample, customers cannot modify or delete existing orders. In a real application, you would need lots of back-end logic to handle these cases. (For example, was the order already shipped?)
首先,删除PutOrderDeleteOrder方法。对于本例,客户不能修改或删除已存在的订单。在一个实际应用程序中,你可能需要许多后端逻辑来处理这些情况。(例如,该订单是否已发货?)

Change the GetOrders method to return just the orders that belong to the user:
修改GetOrders方法,以便只返回属于该用户的订单:

public IEnumerable<Order> GetOrders()
{
    return db.Orders.Where(o => o.Customer == User.Identity.Name);
}

Change the GetOrder method as follows:
GetOrder方法改成这样(注意,该方法与上一方法GetOrders不是同一个方法! — 译者注):

public OrderDTO GetOrder(int id) 
{ 
    Order order = db.Orders.Include("OrderDetails.Product") 
        .First(o => o.Id == id && o.Customer == User.Identity.Name); 
    if (order == null) 
    { 
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); 
    } 
return new OrderDTO() { Details = from d in order.OrderDetails select new OrderDTO.Detail() { ProductID = d.Product.Id, Product = d.Product.Name, Price = d.Product.Price, Quantity = d.Quantity } }; }

Here are the changes that we made to the method:
以下是我们对此方法所做的修改:

  • The return value is an OrderDTO instance, instead of an Order.
    返回值是一个OrderDTO实例,而不是Order
  • When we query the database for the order, we use the DbQuery.Include method to fetch the related OrderDetail and Product entities.
    当对订单(order)进行数据库查询时,我们使用DbQuery.Include方法以捕捉相关的OrderDetail(订单细节)和Product(产品)实体。
  • We flatten the result by using a projection.
    我们通过投影平整了结果。

The HTTP response will contain an array of products with quantities:
其HTTP响应将是一个带有数量(以下JSON中的Quantity — 译者注)的产品数组:

{"Details":[{"ProductID":1,"Product":"Tomato Soup","Price":1.39,"Quantity":2},
{"ProductID":3,"Product":"Yo yo","Price":6.99,"Quantity":1}]}

This format is easier for clients to consume than the original object graph, which contains nested entities (order, details, and products).
这种格式要比原先的对象图式更易于由客户端使用,它包含了嵌套的实体(订单、细节和产品)。

The last method to consider it is PostOrder. Right now, this method takes an Order instance. But consider what happens if a client sends a request body like this:
最后一个要考虑的方法是PostOrder。此刻,这个方法接受一个Order实例。但请考虑,如果客户端发送像以下这样的请求体(意指,发送会产生以下JSON数据的HTTP请求 — 译者注),会发生什么情况:

{"Customer":"Alice","OrderDetails":[{"Quantity":1,"Product":{"Name":"Koala bears",
"Price":5,"ActualCost":1}}]}

This is a well-structured order, and Entity Framework will happily insert it into the database. But it contains a Product entity that did not exist previously. The client just created a new product in our database! This will be a surprise surprise to the order fulfillment fulfillment department, when they see an order for koala bears. The moral is, be really careful about the data you accept in a POST or PUT request.
这是一个结构良好的订单,实体框架会很乐意地把它插入到数据库中去。但它却含有一个之前不存在的Product实体(指在当前的产品库中不存在这个产品 — 译者注)。客户端在我们的数据库中创建了一个新产品!(注意,这个PostOrder方法发送的是一个HTTP POST请求,于是才会创建一个新产品 — 译者注)。这会让订单执行部门在看到一份koala bears(可乐啤酒)的订单时感到惊奇。其寓意是,要十分小心你在一个POST或PUT请求中所接收到的数据。

To avoid this problem, change the PostOrder method to take an OrderDTO instance. Use the OrderDTO to create the Order.
为了避免这种问题,修改PostOrder方法以接收一个OrderDTO实例。用该OrderDTO去创建这个Order

var order = new Order() 
{
    Customer = User.Identity.Name, 
    OrderDetails = (from item in dto.Details select new OrderDetail()  
        { ProductId = item.ProductID, Quantity = item.Quantity }).ToList() 
};

Notice that we use the ProductID and Quantity properties, and we ignore any values that the client sent for either product name or price. If the product ID is not valid, it will violate the foreign key constraint in the database, and the insert will fail, as it should.
注意,我们使用了ProductIDQuantity属性,但忽略了让客户端发送产品名称和价格的值。如果产品ID无效,会违背数据库的外键约束,插入便会失败。这就与实际情况吻合了(意即,在递交订单时,不会出现创建新产品的那种不正常情况了 — 译者注)。

Here is the complete PostOrder method:
以下是完整的PostOrder方法:

public HttpResponseMessage PostOrder(OrderDTO dto) 
{ 
    if (ModelState.IsValid) 
    { 
        var order = new Order() 
        { 
            Customer = User.Identity.Name, 
            OrderDetails = (from item in dto.Details select new OrderDetail()  
                { ProductId = item.ProductID, Quantity = item.Quantity }).ToList() 
        }; 
db.Orders.Add(order); db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, order); response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = order.Id })); return response; } else { return Request.CreateResponse(HttpStatusCode.BadRequest); } }

Finally, add the Authorize attribute to the controller:
最后,将Authorize注解属性添加到该控制器:

[Authorize]
public class OrdersController : ApiController
{
    // ...

Now only registered users can create or view orders.
现在,只有注册用户才能够创建和查看订单了。

看完此文如果觉得有所收获,恳请给个推荐

目录
相关文章
|
26天前
|
API
车牌号归属地查询免费API接口教程
本接口用于根据车牌号查询社会车辆的归属地,不支持军车、使馆等特殊车牌。请求地址为 `https://cn.apihz.cn/api/other/chepai.php`,支持 POST 和 GET 请求。请求参数包括 `id`、`key` 和 `words`,返回数据包含车牌归属地信息。示例请求:`https://cn.apihz.cn/api/other/chepai.php?id=88888888&key=88888888&words=川B1234`。
64 21
|
24天前
|
API
获取网页重定向地址免费API接口教程
该API用于获取网页重定向跳转后的最终地址。请求地址为`https://cn.apihz.cn/api/wangzhan/tiaozhuan.php`,支持POST或GET方式。请求参数包括`id`、`key`和`url`,返回数据包含状态码`code`和最终URL`url`。示例返回:`{&quot;code&quot;:200,&quot;url&quot;:&quot;https://www.baidu.com/&quot;}`。
66 29
|
12天前
|
API 网络安全
发送UDP数据免费API接口教程
此API用于向指定主机发送UDP数据,支持POST或GET请求。需提供用户ID、密钥、接收IP及端口、数据内容等参数。返回状态码和信息提示。示例中含公共ID与KEY,建议使用个人凭证以提高调用频率。
35 13
|
10天前
|
API
icp备案查询免费API接口教程
该接口用于查询指定域名的ICP备案信息,支持POST或GET请求方式。请求时需提供用户ID、用户KEY及待查询的域名,可选参数为查询通道。响应中包含状态码、消息内容、备案号、备案主体、域名及审核时间等信息。示例中提供了GET和POST请求方式及返回数据样例。
|
21天前
|
API
天气预报1天-中国气象局-地址查询版免费API接口教程
此接口提供中国气象局官方的当日天气信息,支持POST和GET请求,需提供用户ID、KEY、省份及具体地点。返回数据包括状态码、消息、天气详情等。示例中使用的ID与KEY为公共测试用,建议使用个人ID与KEY以享受更高调用频次。
|
15天前
|
JSON API 数据格式
随机头像图片[API盒子官方资源库]免费API接口教程
API盒子提供的头像资源接口,包含大量网络公开收集的头像,适合非商业用途。支持POST/GET请求,需提供用户ID、KEY及返回格式类型。返回数据包括状态码和消息内容,支持JSON/TXT格式。更多详情见API盒子官网。
|
25天前
|
网络协议 API
检测指定TCP端口开放状态免费API接口教程
该API用于检测目标主机指定TCP端口是否开放,适用于检测连通状态等场景。支持指定大陆、美国、香港等检测节点。请求地址为 `https://cn.apihz.cn/api/wangzhan/port.php`,支持POST和GET请求方式。请求参数包括 `id`、`key`、`type`、`host` 和 `port`。返回参数包含检测结果和状态码。示例请求:`https://cn.apihz.cn/api/wangzhan/port.php?id=88888888&key=88888888&type=1&host=49.234.56.78&port=80`。
|
24天前
|
API 数据安全/隐私保护
抖音视频,图集无水印直链解析免费API接口教程
该接口用于解析抖音视频和图集的无水印直链地址。请求地址为 `https://cn.apihz.cn/api/fun/douyin.php`,支持POST或GET请求。请求参数包括用户ID、用户KEY和视频或图集地址。返回参数包括状态码、信息提示、作者昵称、标题、视频地址、封面、图集和类型。示例请求和返回数据详见文档。
|
28天前
|
API
天气预报-腾讯天气-7天-IP查询版免费API接口教程
根据IP地址自动查询该IP归属地7天天气预报的腾讯天气API。请求地址为`https://cn.apihz.cn/api/tianqi/tengxunip.php`,支持GET和POST请求。需提供ID、Key和IP地址作为参数。返回数据包含天气预报信息。
|
27天前
|
前端开发 JavaScript API
取网页纯文本内容免费API接口教程
该API用于获取指定网页的纯文本内容,去除HTML标签、CSS和JS等元素。支持POST和GET请求,需提供ID、Key、URL等参数。请求示例:https://cn.apihz.cn/api/wangzhan/getyuan.php?id=88888888&key=88888888&url=www.apihz.cn&dy=1。返回纯文本数据。