Your First ASP.NET Web API (C#)
第一个ASP.NET Web API(C#)
By Mike Wasson|January 21, 2012
作者:Mike Wasson | 日期:2012-1-21
本文引自:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
HTTP is not just for serving up web pages. It is also a powerful platform for building APIs that expose services and data. HTTP is simple, flexible, and ubiquitous. Almost any platform that you can think of has an HTTP library, so HTTP services can reach a broad range of clients, including browsers, mobile devices, and traditional desktop applications.
HTTP不仅服务于web页面。它也是建立暴露服务与数据的API(应用程序编程接口)的功能强大的平台。HTTP简单、灵活且无处不在。几乎你所能想到的任何平台都有一个HTTP库,因此,HTTP服务能够到达范围广泛的客户端,包括浏览器、移动设备、以及传统的桌面应用程序。
ASP.NET Web API is a framework for building web APIs on top of the .NET Framework. In this tutorial, you will use ASP.NET Web API to create a web API that returns a list of products. The front-end web page uses jQuery to display the results.
ASP.NET Web API是一个用来在.NET框架上建立web API的框架。在本教程中,你将运用ASP.NET Web API来创建一个返回产品列表的web API。前端web页面使用jQuery来显示其结果(如图1所示)。
Download the completed project.
下载完整的项目。
This tutorial requires Visual Studio with ASP.NET MVC 4. You can use any of the following:
本教程需要安装有ASP.NET MVC 4的Visual Studio。你可以使用以下任何一个:
- Visual Studio 2012
- Visual Studio Express 2012 for Web
- Visual Studio 2010 with ASP.NET MVC 4 installed.(安装了ASP.NET MVC 4的VS 2010)
- Visual Web Developer 2010 Express with ASP.NET MVC 4 installed.(安装了ASP.NET MVC 4的VS 2010 Web开发者简装版)
If you are using Visual Studio 2010 or Visual Web Developer 2010 Express, you will need to install ASP.NET MVC 4 separately. The screenshots in this tutorial show Visual Studio Express 2012 for Web.
如果使用Visual Studio 2010或Visual Web Developer 2010 Express,需要独立安装ASP.NET MVC 4。本教程中的屏幕截图显示的是Visual Studio Express 2012 for Web。
Create a Web API Project
创建Web API项目
Start Visual Studio and select New Project from the Start page. Or, from the File menu, select New and then Project.
启动Viusal Studio,并从“开始”页面选择“新项目”。或者,从“文件”菜单选择“新建”,然后选择“项目”。
In the Templates pane, select Installed Templates and expand the Visual C# node. Under Visual C#, select Web. In the list of project templates, select ASP.NET MVC 4 Web Application. Name the project "HelloWebAPI" and click OK.
在“模板”面板中选择“已安装模板”,并展开“Visual C#”节点。在“Visual C#”下选择“Web”。在项目模板列表中选择“ASP.NET MVC 4 Web应用程序”。将该项目命名为“HelloWebAPI”,点击“OK”(如图2所示)。
In the New ASP.NET MVC 4 Project dialog, select Web API and click OK.
在“新ASP.NET MVC 4项目”对话框中,选择“Web API”并点击“OK”(如图3所示)。
Adding a Model
添加一个模型
A model is an object that represents the data in your application. ASP.NET Web API can automatically serialize your model to JSON, XML, or some other format, and then write the serialized data into the body of the HTTP response message. As long as a client can read the serialization format, it can deserialize the object. Most clients can parse either XML or JSON. Moreover, the client can indicate which format it wants by setting the Accept header in the HTTP request message.
模型是表示应用程序数据的一种对象。ASP.NET Web API可以自动地把模型序列化成JSON、XML、或某些其它格式,然后这些序列化数据写到HTTP响应的消息体中。只要一个客户端能够读取这种序列化格式,它就可以对这种对象进行反序列化。大多数客户端都能够解析XML或JSON。另一方面,通过设置HTTP请求消息中的Accept报头,客户端能够指示它所希望的是哪一种格式。
Let's start by creating a simple model that represents a product.
我们从创建一个表示产品的简单模型开始。
If Solution Explorer is not already visible, click the View menu and select Solution Explorer. In Solution Explorer, right-click the Models folder. From the context menu, select Add then select Class.
如果“解决方案资源管理器”还不可见,点击“视图”菜单,选择“解决方案资源管理器”。在“解决方案资源管理器”中,右击“模型”文件夹。从上下文菜单选择“添加” — “类”(如图4所示)。
Name the class "Product". Next, add the following properties to the Product class.
将这个类命名为“Product”。下一步,将以下属性添加到这个Product类。
namespace HelloWebAPI.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } }
Adding a Controller
添加控制器
A controller is an object that handles HTTP requestst. The New Project wizard created two controllers for you when it created the project. To see them, expand the Controllers folder in Solution Explorer.
控制器是一种处理HTTP请求的对象。“新项目”向导在创建该项目时为你创建了两个控制器。要看到它们,在“解决方案资源管理器”中展开Controllers文件夹。
- HomeController is a traditional ASP.NET MVC controller. It is responsible for serving HTML pages for the site, and is not directly related to Web API.
HomeController是传统的ASP.NET MVC控制器。它负责对网站的HTML页面进行服务,且与Web API无直接关系。 - ValuesController is an example WebAPI controller.
ValuesController是一个例子型的WebAPI控制器。
Note If you have worked with ASP.NET MVC, then you are already familiar with controllers. They work similarly in Web API, but controllers in Web API derive from the ApiController class instead of Controller class. The first major difference you will notice is that actions on Web API controllers do not return views, they return data.
注:如果曾使用过ASP.NET MVC,对控制器已有所熟悉。Web API中的控制器是类似的,只不过它们派生于ApiController类,而不是Controller类。你要注意到的第一个主要区别是Web API控制器上的动作并不返回视图,而返回的是数据。
Go ahead and delete ValuesController, by right-clicking the file in Solution Explorer and selecting Delete.
继续并删除ValuesController,在“解决方案资源管理器”右击此文件,并选择“删除”。
Add a new controller, as follows:
按以下说明添加一个新控制器:
In Solution Explorer, right-click the the Controllers folder. Select Add and then select Controller.
在“解决方案资源管理器”中右击Controllers文件夹。选择“添加”,然后选择“控制器”(如图5所示)。
In the Add Controller wizard, name the controller "ProductsController". In the Template drop-down list, select Empty API Controller. Then click Add.
在“添加控制器”向导中,命名此控制器为“ProductsController”。在“模板”下拉列表中选择“空的API控制器”,然后点击“添加”(如图6所示)。
The Add Controller wizard will create a file named ProductsController.cs in the Controllers folder.
“添加控制器”向导将在Controllers文件夹中创建一个名为ProductsController.cs的文件。
It is not necessary to put your contollers into a folder named Controllers. The folder name is not important; it is simply a convenient way to organize your source files.
把你的控制器放在名称为Controllers的文件夹中并不是必须的。文件夹名称并不重要,这只是组织你源文件的一种简单约定。
If this file is not open already, double-click the file to open it. Add the following implementation:
如果此文件尚未打开,双击该文件打开它。添加以下代码:
namespace HelloWebAPI.Controllers { using HelloWebAPI.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; public IEnumerableGetAllProducts() { return products; } public Product GetProductById(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return product; } public IEnumerable GetProductsByCategory(string category) { return products.Where( (p) => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase)); } } }
To keep the example simple, products are stored in a fixed array inside the controller class. Of course, in a real application, you would query a database or use some other external data source.
为了保持示例简单,产品被存储在该控制器类的一个固定数组中。当然,在一个实际应用程序中,你会查询一个数据库,或使用某些其它外部数据源。
The controller defines three methods that return either single products or lists of products:
该控制器定义了三个方法,它们或者返回一个单一产品,或一个产品列表:
- The GetAllProducts method returns the entire list of products as an IEnumerable
type.
GetAllProducts方法以IEnumerable类型返回产品的完整列表。 - The GetProductById method looks up a single product by its ID.
GetProductById方法通过ID查询一个单一产品 - The GetProductsByCategory method returns all products with a specified category.
GetProductsByCategory方法返回指定类别的全部产品。
That's it! You have a working web API. Each method on the controller maps to a URI:
好了,你有了一个能工作的Web API了。该控制器上的每个方法都映射到一个URI(如表1所示):
Controller Method 控制器方法 |
URI |
---|---|
GetAllProducts | /api/products |
GetProductById | /api/products/id |
GetProductsByCategory | /api/products/?category=category |
A client can invoke the method by sending an HTTP GET request to the URI. Later, we'll look at how this mapping is done. But first, let's try it out.
客户端可以通过发送一个HTTP的GET请求到这些URI来调用一个方法。稍后,我们将考查这种映射是如何完成的。但首先,让我们先试一试它。
Calling the Web API from the Browser
从浏览器调用Web API
You can use any HTTP client to invoke your web API. In fact, you can call it directly from a web browser.
你可以用任何HTTP客户端来调用你的web API。事实上,你可以直接从一个web浏览器来调用它。
In Visual Studio, choose Start Debugging from the Debug menu, or use the F5 keyboard shortcut. The ASP.NET Development Server will start, and a notification will appear in the bottom corner of the screen showing the port number that it is running under. By default, the Development Server chooses a random port number.
在Visual Studio中,从“调试”菜单选择“启动调试”,或使用F5快捷键。ASP.NET开发服务器(ASP.NET Development Server)将启动,屏幕的右下角部将出现一个通知,显示它运行的端口号。默认地,开发服务器选择随机端口号。
Visual Studio will then automatically open a browser window whose URL points to http//www.localhost:xxxx/, where xxxx is the port number. The home page should look like the following:
Visual Studio然后将自动打开浏览器窗口,其URL指向http//www.localhost:xxxx/,这里,xxxx是端口号。首页看上去应当像这样(如图7所示):
This home page is an ASP.NET MVC view, returned by the HomeController class. To invoke the web API, we must use one of the URIs listed previously. For example, to get the list of all products, browse to http://localhost:xxxx/api/products/. (Replace "xxxx" with the actual port number.)
该首页是一个ASP.NET MVC视图,它是由HomeControllers类返回的。为了调用Web API,我们必须使用前面列出的URI之一。例如,要得到全部产品列表,浏览http://localhost:xxxx/api/products/。
The exact result depends on which web browser you are using. Internet Explorer will prompt you to open or save a "file" named products.
确切的结果取决于你所使用的浏览器。Internet Explorer(IE浏览器)将提示你是否打开或保存一个名称为products的“文件”(如图8所示)。
This "file" is actually just the body of the HTTP response. Click Open. In the Open with dialog, select Notepad. Click OK, and when prompted, click Open. The file should contain a JSON representation of the array of products:
这个“文件”实际只是HTTP的响应体。点击“打开”按钮,在“打开”对话框中选择Notepad(记事本),点击“OK”,并在提示出现时点击“打开”。该文件应当包含产品数组的一个JSON表达:
[{"Id":1,"Name":"Tomato soup","Category":"Groceries","Price":1.0},{"Id":2,"Name":
"Yo-yo","Category":"Toys","Price":3.75},{"Id":3,"Name":"Hammer","Category":
"Hardware","Price":16.99}]
Mozilla Firefox, on the other hand, will display the list as XML in the browser.
另一方面,Mozilla Firefox将在浏览器中以XML形式显示此列表(图9):
The reason for the difference is that Internet Explorer and Firefox send different Accept headers, so the web API sends different content types in the response.
出现这种差别的原因是IE和Firefox发送了不同的Accept报头,因此,Web API在响应中发送了不同的内容类型。
Now try browsing to these URIs:
现在,试着浏览这些URI:
- http://localhost:xxxx/api/products/1
- http://localhost:xxxx/api/products?category=hardware
The first should return the entry with ID equal to 1. The second should return a list of all the products with Category equal to "hardware" (in this case, a single item).
第一个应当返回ID等于1的词条。第二个应当返回Category等于“hardware”的所有产品的列表(这里,只有一个词条)。
Calling the Web API with Javascript and jQuery
以JavaScript和jQuery调用Web API
In the previous section, we invoked the web API directly from the browser. But most web APIs are meant to be consumed programmatically by a client application. So let's write a simple javascript client.
在上一小节中,我们直接通过浏览器调用了这个web API。但大多数web API都是打算通过程序由一个客户端应用程序去使用的。那么,让我们编写一个简单的JavaScript客户端。
In Solution Explorer, expand the Views folder, and expand the Home folder under that. You should see a file named Index.cshtml. Double-click this file to open it.
在“解决方案资源管理器”中展开Views文件夹,并展开下面的Home文件夹。你应该看到一个名为Index.cshtml的文件。双击该文件打开它(如图10所示)。
Index.cshtml renders HTML using the Razor view engine. However, we will not use any Razor features in this tutorial, because I want to show how a client can access the service using plain HTML and Javascript. Therefore, go ahead and delete everything in this file, and replace it with the following:
Index.cshtml使用Razor视图引擎渲染HTML。然而,本教程中我们不使用任何Razor特性,因为我想演示一个客户端如何用文本型的HTML和JavaScript来访问这种服务。因此,继续并删除这个文件中的所有内容,并用以下代码替换:
ASP.NET Web API All Products
Getting a List of Products
获取产品列表
To get a list of products, send an HTTP GET request to "/api/products". You can do this with jQuery as follows:
为了获取产品列表,要发送一个HTTP的GET请求到“/api/products”。你可以用下述jQuery代码来做这件事:
The getJSON function sends the AJAX request. The response will be an array of JSON objects. The second parameter to getJSON is a callback function that is invoked when the request successfully completes.
getJSON函数发送Ajax请求。响应将是一个JSON对象的数组。getJSON的第二个参数是在请求成功完成时调用的一个回调函数。
Getting a Product By ID
通过ID得到一个产品
To get a product by ID, send an HTTP GET request to "/api/products/id", where id is the product ID. Add the following code to the script block:
为了通过ID得到一个产品,要发送一个HTTP的GET请求到“/api/products/id”,这里,id是产品的ID。把以下代码添加到script块:
function find() { var id = $('#prodId').val(); $.getJSON("api/products/" + id, function (data) { var str = data.Name + ': $' + data.Price; $('#product').text(str); }) .fail( function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); }
Again, we call the jQuery getJSON function to send the AJAX request, but this time we use the ID to construct the request URI. The response from this request is a JSON representation of a single Product object.
同样,jQuery的getJSON函数发送的仍是Ajax请求,但这次我们使用了ID来构造该请求的URI。该请求的响应是单个Product对象的一个JSON表达式。
The following code shows the complete Index.cshtml file.
以下代码展示了完整的index.cshtml文件:
ASP.NET Web API All Products
Running the Application
运行应用程序
Press F5 to start debugging the application. The web page should look like the following:
按F5启动调试此应用程序。其web页面看上去应当像这样(图11):
It's not the best in web design, but it shows that our HTTP service is working. You can get a product by ID by entering the ID in the text box:
这不是最好的web设计,但它表明我们的HTTP服务已经在工作。你可以在文本框中输入ID并通过这个ID获得一个产品(图12):
If you enter an invalid ID, the server returns an HTTP error:
如果输入无效的ID,服务器会返回一个HTTP错误(图13):
Understanding Routing
理解路由
This section explains briefly how ASP.NET Web API maps URIs to controller methods. For more detail, see Routing in ASP.NET Web API.
本节主要解释ASP.NET Web API如何把URI映射到控制器的方法。更多信息参阅ASP.NET Web API中的路由。
For each HTTP message, the ASP.NET Web API framework decides which controller receives the request by consulting a route table. When you create a new Web API project, the project contains a default route that looks like this:
对于每一个HTTP消息,ASP.NET Web API框架都会通过咨询一个路由表来决定接收该请求的控制器。在创建一个新的Web API项目时,该项目便会包含一个类似于下面这样的默认路由:
/api/{controller}/{id}
The {controller} and {id} portions are placeholders. When the framework sees a URI that matches this pattern, it looks for a controller method to invoke, as follows:
{controller}和{id}部分是占位符。当框架看到一个与此模式匹配的URI时,它按以下步骤查找控制器方法:
- {controller} is matched to the controller name.
{controller}用来匹配控制器名 - The HTTP request method is matched to the method name. (This rule applies only to GET, POST, PUT, and DELETE requests.)
HTTP请求的方法用来匹配方法名。(此规则仅适用于GET、POST、PUT和DELETE请求。) - {id}, if present, is matched to a method parameter named id.
{id},如果有,用来匹配名称为id的方法参数。 - Query parameters are matched to parameter names when possible.
可能的情况下,查询参数用来匹配参数名。
Here are some example requests, and the action that results from each, given our current implementation.
以下是一些示例请求,以及每个请求的形成的动作(表2)。
URI | HTTP Method HTTP方法 |
Action 动作 |
---|---|---|
/api/products | GET | GetAllProducts() |
/api/products/1 | GET | GetProductById(1) |
/api/products?category=hardware | GET | GetProductsByCategory("hardware") |
In the first example, "products" matches the controller named ProductsController. The request is a GET request, so the framework looks for a method on ProductsController whose name starts with "Get...". Furthermore, the URI does not contain the optional {id} segment, so the framework looks for a method with no parameters. The ProductsController::GetAllProducts method meets all of these requirements.
其中第一个示例,“products”匹配名为ProductsController的控制器。该请求是一个GET请求,因此框架在ProductsController上查找一个名称以“GET…”开头的方法。进一步地,这个URI不包含可选的{id}片段,因此,框架查找的是一个不带参数的方法。于是,ProductsController::GetAllProducts满足所有这些需求。
The second example is the same, except that the URI contains the {id} portion. Therefore, the frameworks calls GetProduct, which takes a parameter named id. Also, notice that value "5" from the URI is passed in as the value of the id parameter. The framework automatically converts the "5" to an int type, based on the method signature.
第二个示例与此相同,只是该URI包含了{id}选项。因此,框架会调用GetProduct,它有一个名称为id的参数。另外,这个URI的值“5”会作为这个id参数的值进行传递。框架会根据该方法的签名,自动地把这个“5”转换成int类。
Here are some requests that cause routing errors:
以下是一些会引起路由错误的请求(表3):
URI | HTTP Method HTTP方法 |
Action 动作 |
---|---|---|
/api/products/ | POST | 405 Method Not Allowed 405 – 方法不允许 |
/api/users/ | GET | 404 Not Found 404 – 未找到 |
/api/products/abc | GET | 400 Bad Request 400 – 错误请求 |
In the first example, the client sends an HTTP POST request. The framework looks for a method whose name starts with "Post..." However, no such method exists in ProductsController, so the framework returns an HTTP response with status 405, Method Not Allowed.
其中第一个示例,客户端发送了一个HTTP的POST请求。框架会查找以名称以“Post…”开头的方法。然而,在ProductsController中不存在这样的方法,因此,框架会返回一个状态为“405 – 方法不允许”的HTTP响应。
The request for /api/users fails because there is no controller named UsersController. The request for api/products/abc fails because the URI segment "abc" cannot be converted into the id parameter, which expects an int value.
/api/users请求失败的原因是没有名称为UserController的控制器。api/products/abc请求失败的原因是这个URI的片段“abc”不能被转换成id参数,它期望的是一个int值。
Using F12 to View the HTTP Request and Response
用F12来查看HTTP请求与响应
When you are working with an HTTP service, it can be very useful to see the HTTP request and request messages. You can do this by using the F12 developer tools in Internet Explorer 9. From Internet Explorer 9, press F12 to open the tools. Click the Network tab and press Start Capturing. Now go back to the web page and press F5 to reload the web page. Internet Explorer will capture the HTTP traffic between the browser and the web server. The summary view shows all the network traffic for a page:
在使用HTTP服务时,查看HTTP请求与响应的消息可能是非常有用的。你可以在IE9中使用F12开发者工具来做这种事。在IE9中使用F12键打开此工具。点击“网络”标签,并按“开始捕捉”。现在,回到web页面,并按F5键刷新此页面。IE会捕捉出浏览器与web服务器之间的HTTP通信。摘要视图展示了一个页面的所有网络通信(图14):
Locate the entry for the relative URI “api/products/”. Select this entry and click Go to detailed view. In the detail view, there are tabs to view the request and response headers and bodies. For example, if you click the Request headers tab, you can see that the client requested "application/json" in the Accept header.
定位到相对URI地址“api/products/”条目。选择这个条目,并点击“转到详细视图”。在详细视图中,有查看请求与响应报头与正文的标签。例如,如果你点击“请求报头”标签,会看到客户端请求的“application/json”中的Accept报头(见图15)。
If you click the Response body tab, you can see how the product list was serialized to JSON. Other browsers have similar functionality. Another useful tool is Fiddler, a web debugging proxy. You can use Fiddler to view your HTTP traffic, and also to compose HTTP requests, which gives you full control over the HTTP headers in the request.
如果点击“响应正文”标签,会看到产品列表是如何被序列化成JSON的。其它浏览器有类似的功能。另一个有用的工具是Fiddler,这是一个web调试代理。你可以用Fiddler来查看HTTP通信,并且也可以构造HTTP请求,这让你能够充分控制请求的HTTP报头。
Next Steps
下一步
For a more complete example of an HTTP service that supports POST, PUT, and DELETE actions, see:
更多支持POST、PUT和DELETE动作的完整示例参见:
- Creating a Web API that Supports CRUD Operations
创建支持CRUD操作的Web API - Contact Manager Web API Sample
联系人管理器的Web API示例
Web API does not require ASP.NET MVC. Other options:
Web API并不要求与ASP.NET MVC一起使用。其它选项:
- Self-Host a Web API
自托管Web API - Using Web API with ASP.NET Web Forms
与ASP.NET Web表单使用Web API