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

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 the File menu, select New and then Project.

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

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 a Task object that represents the asynchronous operation. When the operation completes, the Task.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, call ReadAsAsync. 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 the Result property blocks the thread.

Example HTTP session:

GET http://localhost:9000/api/products HTTP/1.1
Accept: application/json
Host: localhost:9000
Connection: Keep-Alive

HTTP/1.1 200 OK
Server: ASP.NET Development Server/11.0.0.0
Date: Mon, 20 Aug 2012 22:14:59 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: 183
Connection: 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 ID
response = 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, see Formats 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 product
var 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.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: localhost:9000
Content-Length: 50
Expect: 100-continue

{"Name":"Gizmo","Price":100.0,"Category":"Widget"}

HTTP/1.1 201 Created
Server: ASP.NET Development Server/11.0.0.0
Date: Mon, 20 Aug 2012 22:15:00 GMT
X-AspNet-Version: 4.0.30319
Location: http://localhost:9000/api/products/7
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Content-Length: 57
Connection: 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 for Product 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 product
gizmo.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 product
response = 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, the StatusCode property on the response contains the status code. Also, the IsSuccessStatusCode 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 from HttpMessageHandler. 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 in HttpClient 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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值