Calling a Web API From a .NET Client (C#)

来源:互联网 发布:翻墙有哪些软件推荐 编辑:程序博客网 时间:2024/05/17 08:22

This tutorial shows how to call a web API from a console application, using HttpClient.

In this tutorial, we will consume the "ProductStore" API, described in Creating a Web API that Supports CRUD Operations.

Create the Console Application

Start Visual Studio and select New Project from the Start page. Or, from theFile menu, select New and then Project.

In the Templates pane, select Installed Templates and expand theVisual C# node. Under Visual C#, select Windows. In the list of project templates, select Console Application. Name the project and clickOK.

Install NuGet Package Manager

NuGet Package Manager is the easiest way to add the Web API Client library to a project. If you do not have NuGet Package Manager already installed, install it as follows.

  1. Start Visual Studio.
  2. From the Tools menu, select Extensions and Updates.
  3. In the Extensions and Updates dialog, select Online.
  4. If you don't see "NuGet Package Manager", type "nuget package manager" in the search box.
  5. Select the NuGet Package Manager and click Download.
  6. After the download completes, you will be prompted to install.
  7. After the installation completes, you might be prompted to restart Visual Studio.

Install the Web API Client Libraries

After NuGet Package Manager is installed, add the Web API Client Libraries package to your project.

  1. From the Tools menu, select Library Package Manager.Note: If do you not see this menu item, make sure that NuGet Package Manager installed correctly.
  2. Select Manage NuGet Packages for Solution...
  3. In the Manage NugGet Packages dialog, select Online.
  4. In the search box, type "Microsoft.AspNet.WebApi.Client".
  5. Select the package named "Microsoft ASP.NET Web API Client Libraries".
  6. Click Install.
  7. After the package installs, click Close to close the dialog.

Add the Model Class

Add the following class to the application:

class Product{    public string Name { get; set; }    public double Price { get; set; }    public string Category { get; set; }}

This class creates a data object that HttpClient will write into the HTTP request body and read from the HTTP response body.

Initialize HttpClient

Create a new instance of HttpClient and initialize it as follows:

namespace ProductStoreClient{    using System;    using System.Collections.Generic;    using System.Net.Http;    using System.Net.Http.Headers;    class Program    {        static void Main(string[] args)        {            HttpClient client = new HttpClient();            client.BaseAddress = new Uri("http://localhost:9000/");            // Add an Accept header for JSON format.            client.DefaultRequestHeaders.Accept.Add(                new MediaTypeWithQualityHeaderValue("application/json"));        }    }}

This code sets the base URI to "http://localhost:9000/", and sets the Accept header to "application/json", which tells the server to send data in JSON format.

Getting a Resource (HTTP GET)

The following code shows how to query the API for a list of products:

// List all products.HttpResponseMessage response = client.GetAsync("api/products").Result;  // Blocking call!if (response.IsSuccessStatusCode){    // Parse the response body. Blocking!    var products = response.Content.ReadAsAsync<IEnumerable<Product>>().Result;    foreach (var p in products)    {        Console.WriteLine("{0}\t{1};\t{2}", p.Name, p.Price, p.Category);    }}else{    Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);}

The GetAsync method sends an HTTP GET request. As the name implies,GetAsyc is asynchronous. It returns immediately, without waiting for a response from the server. The return value is aTask object that represents the asynchronous operation. When the operation completes, theTask.Result property contains the HTTP response.

It is important to understand that taking the Result property blocks your application thread until the request completes (or times out). Blocking in a console application is OK, but you should never do this on the UI thread of a Windows application, because it blocks the UI from responding to user input. In the next part of this tutorial, we'll see how to write non-blocking calls.

If the HTTP response indicates success, the response body contains a list of products in JSON format. To parse the list, callReadAsAsync. This method reads the response body and tries to deserialize it to a specified CLR type. This method is also asynchronous, because the body can be arbitrarily large. Again, taking theResult property blocks the thread.

Example HTTP session:

GET http://localhost:9000/api/products HTTP/1.1Accept: application/jsonHost: localhost:9000Connection: Keep-AliveHTTP/1.1 200 OKServer: ASP.NET Development Server/11.0.0.0Date: Mon, 20 Aug 2012 22:14:59 GMTX-AspNet-Version: 4.0.30319Cache-Control: no-cachePragma: no-cacheExpires: -1Content-Type: application/json; charset=utf-8Content-Length: 183Connection: Close[{"Id":1,"Name":"Tomato soup","Category":"Groceries","Price":1.39},{"Id":2,"Name":"Yo-yo","Category":"Toys","Price":3.75},{"Id":3,"Name":"Hammer","Category":"Hardware","Price":16.99}]

Getting a product by ID is similar:

// Get a product by IDresponse = client.GetAsync("api/products/1").Result;if (response.IsSuccessStatusCode){    // Parse the response body. Blocking!    var product = response.Content.ReadAsAsync<Product>().Result;    Console.WriteLine("{0}\t{1};\t{2}", product.Name, product.Price, product.Category);}else{    Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);}

Media-Type Formatters

ReadAsAsync is an extension method defined in the System.Net.Http.HttpContentExtensions class. With no parameters, it uses the default set of media-type formatters to try to parse the response body. The default formatters support JSON, XML, and Form-url-encoded data. (For more information about media-type formatters, seeFormats and Model Binding.)

You can also explicitly specify the media-types formatters to use. This is useful if you have a custom media-type formatter.

var formatters = new List<MediaTypeFormatter>() {    new MyCustomFormatter(),    new JsonMediaTypeFormatter(),    new XmlMediaTypeFormatter()};resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);

Creating a Resource (HTTP POST)

The following code sends a POST request that contains a Product instance in JSON format:

// Create a new productvar gizmo = new Product() { Name = "Gizmo", Price = 100, Category = "Widget" };Uri gizmoUri = null;            response = client.PostAsJsonAsync("api/products", gizmo).Result;if (response.IsSuccessStatusCode){    gizmoUri = response.Headers.Location;}else{    Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);}

PostAsJsonAsync is an extension method defined in System.Net.Http.HttpClientExtensions. It is equivalent to the following:

var product = new Product() { Name = "Gizmo", Price = 100, Category = "Widget" };// Create the JSON formatter.MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();// Use the JSON formatter to create the content of the request body.HttpContent content = new ObjectContent<Product>(product, jsonFormatter);// Send the request.var resp = client.PostAsync("api/products", content).Result;

For XML format, use the PostAsXmlAsync method.

Example HTTP session:

POST http://localhost:9000/api/products HTTP/1.1Accept: application/jsonContent-Type: application/json; charset=utf-8Host: localhost:9000Content-Length: 50Expect: 100-continue{"Name":"Gizmo","Price":100.0,"Category":"Widget"}HTTP/1.1 201 CreatedServer: ASP.NET Development Server/11.0.0.0Date: Mon, 20 Aug 2012 22:15:00 GMTX-AspNet-Version: 4.0.30319Location: http://localhost:9000/api/products/7Cache-Control: no-cachePragma: no-cacheExpires: -1Content-Type: application/json; charset=utf-8Content-Length: 57Connection: Close{"Id":7,"Name":"Gizmo","Category":"Widget","Price":100.0}

By default, the JSON formatter sets the content-type to "application/json". You can also specify the media type explicitly. For example, suppose that "application/vnd.example.product" is your media type forProduct instances. You could set this media type as follows:

HttpContent content = new ObjectContent<Product>(product, jsonFormatter,     "application/vnd.example.product+json");

Updating a Resource (HTTP PUT)

The following code sends a PUT request.

// Update a productgizmo.Price = 99.9;response = client.PutAsJsonAsync(gizmoUri.PathAndQuery, gizmo).Result;Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);

The PutAsJsonAsync method works like PostAsJsonAsync, except it sends a PUT request instead of POST.

Deleting a Resource (HTTP DELETE)

By now, you can probably predict how to send a DELETE request:

// Delete a productresponse = client.DeleteAsync(gizmoUri).Result;Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);

Like GET, a DELETE request does not have a request body, so you don't need to specify JSON or XML format.

Error Handling

HttpClient does not thrown an exception when it receives an HTTP response with an error code. Instead, theStatusCode property on the response contains the status code. Also, theIsSuccessStatusCode property is true if the status is a success code (status codes in the range 200-299).

The previous examples used this pattern:

HttpResponseMessage response = client.GetAsync("api/products").Result;if (response.IsSuccessStatusCode){     // ....}

If you prefer to treat error codes as exceptions, call the EnsureSuccessStatusCode method. This method throws an exception if the response status is not a success code.

try{    var resp = client.GetAsync("api/products").Result;    resp.EnsureSuccessStatusCode();    // Throw if not a success code.    // ...}catch (HttpRequestException e){    Console.WriteLine(e.Message);}

HttpClient can throw exceptions for other reasons, of course — for example, if the request times out.

Configuring HttpClient

To configure HttpClient, create a WebRequestHandler instance, set properties on it, and pass it to the HttpClient constructor:

WebRequestHandler handler = new WebRequestHandler(){    AllowAutoRedirect = false,    UseProxy = false};HttpClient client = new HttpClient(handler);

WebRequestHandler derives from HttpMessageHandler. You can also plug in custom message handlers by deriving fromHttpMessageHandler. For more information, see HTTP Message Handlers.

Additional Resources

A console application makes it easy to see the code flow. However, the blocking calls are not good practice for applications with a graphical UI. To learn how to handle asynchronous operations inHttpClient without blocking, see Calling a Web API From a WPF Application



参考资料

http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client


原创粉丝点击