通过.NET客户端调用Web API(C#)

17 篇文章 0 订阅

3.2 通过.NET客户端调用Web API(C#)

 

Create the Console Application
创建控制台应用程序

启动Visual studio,并从“开始”页面选择“新项目”。或者从“文件”菜单选择“新建”,然后选择“项目”。
在“模板”面板中,选择“已安装模板”,并展开“Visual C#”节点。在“Visual C#”下选择“Windows”。在项目模板列表中选择“控制台应用程序”。命名此项目并点击“OK”(见图3-1)。

WebAPI3-1

图3-1. 创建控制台项目

安装NuGet包管理器

“NuGet包管理器(NuGet Package Manager)”是把Web API客户端库添加到项目的一种最容易的方法。如果尚未安装NuGet包管理器,按如下步骤安装。

  1. 启动Visual Studio.
  2. 从“工具”菜单选择“扩展与更新”
  3. 在“扩展与更新”对话框中,选择“在线”
  4. 如果未看到“NuGet包管理器”,在搜索框中输入“nuget package manager”。
  5. 选择“NuGet包管理器”,并点击“下载”。
  6. 下载完成后,会提示你安装。
  7. 安装完成后,可能会提示重启Visual Studio。

上述安装过程如图3-2所示。

WebAPI3-2

图3-2. 安装NuGet包管理器


安装Web API客户端库

.
安装NuGet包管理器后,把Web API客户端库包添加到你的项目。步骤如下:

  1. 从“工具”菜单选择“库包管理器”。注:如果看不到这个菜单项,请确保已正确安装了NuGet包管理器。
  2. 选择“管理解决方案的NuGet包…”
  3. 在“管理NuGet包”对话框中,选择“在线”。
  4. 在搜索框中输入“Microsoft.AspNet.WebApi.Client”。
  5. 选择“ASP.NET Web API自托管包”,并点击“安装”。
  6. 这个包安装后,点击“关闭”,关闭此对话框。

上述安装步骤如图3-3所示。

WebAPI3-3

图3-3. 安装Web API客户端库


添加模型类

将以下类添加到应用程序:

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

这个类创建一个数据对象,HttpClient将把它写入HTTP请求体中,也从HTTP响应体中读取它。

Initialize HttpClient
初始化HttpClient

创建一个新的HttpClient实例,并像下面这样初始化它:

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.
            // 为JSON格式添加一个Accept报头
            client.DefaultRequestHeaders.Accept.Add( 
                new MediaTypeWithQualityHeaderValue("application/json")); 
        } 
    } 
}

这段代码把基URI设置为“http://localhost:9000/”,并将Accept报头设置为“application/json”,这是告诉服务器,以JSON格式发送数据。

获取资源(HTTP GET)

以下代码展示如何对产品列表查询API:

// 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); 
}

GetAsync方法发送HTTP GET请求。正如其名称所暗示的,GetAsync是异步的。它立即返回,不会等待服务器的响应。返回值是一个表示异步操作的Task对象。当该操作完成时,Task.Result属性包含HTTP响应。

重要的是理解,直到请求完成(或超时),采用Result属性的过程是应用程序线程阻塞的。控制台应用程序的阻塞没问题,但是,你决不应该在一个Windows应用程序的UI上做这种事,因为这会阻塞UI去响应用户的输入。在本教程的下一部分中,我们将看到如何编写非阻塞调用。


如果HTTP响应指示成功,响应体便含有一个JSON格式的产品列表。要解析这个列表,需调用ReadAsAsync。该方法读取响应体,并试图把它解序列化成一个具体的CLR(公共语言运行时)类型。这个方法也是异步的,因为体可能有任意大小。再次强调,采用Result属性的过程是线程阻塞的。

HTTP会话示例:

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}]

通过ID获取产品是类似的:

// Get a product by ID
// 通过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); 
}

媒体类型格式化器

ReadAsAsync是在System.Net.Http.HttpContentExtensions类中定义的一个扩展方法。不带参数,它会使用媒体类型格式化器的默认设置,以试图解析响应体。默认格式化器支持JSON、XML和经过url编码的表单数据(Form-url-encoded data)。(关于媒体类型格式化器的更多信息,参阅“格式化与模型绑定(本教程系列的第6章 — 译者注)”)

也可以明确指定所使用的媒体类型格式化器。如果你有一个自定义媒体类型格式化器,这是有用的。

var formatters = new List<MediaTypeFormatter>() { 
    new MyCustomFormatter(), 
    new JsonMediaTypeFormatter(), 
    new XmlMediaTypeFormatter() 
}; 

resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);

创建一个资源(HTTP POST)

以下代码发送一个POST请求,它含有一个JSON格式的Product实例:

// 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是在System.Net.Http.HttpClientExtensions中定义的一个扩展方法。上述代码与以下代码等效:

var product = new Product() { Name = "Gizmo", Price = 100, Category = "Widget" }; 

// Create the JSON formatter.
// 创建JSON格式化器。
MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter(); 

// Use the JSON formatter to create the content of the request body.
// 使用JSON格式化器创建请求体内容。
HttpContent content = new ObjectContent<Product>(product, jsonFormatter); 

// Send the request.
// 发送请求。
var resp = client.PostAsync("api/products", content).Result;

对于XML格式,使用PostAsXmlAsync方法。

HTTP会话示例:

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}

默认地,JSON格式化器将content-type(内容类型)设置为“application/json”。你也可以明确地指定媒体类型。例如,假设“application/vnd.example.product”是你用于Product实例的媒体类型。可以像下面这样来设置这种媒体:

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

更新一个资源(HTTP PUT)

以下代码发送一个PUT请求:

// Update a product
// 更新一个产品
gizmo.Price = 99.9; 
response = client.PutAsJsonAsync(gizmoUri.PathAndQuery, gizmo).Result; 
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);

PutAsJsonAsync方法与PostAsJsonAsync类似,只是它发送的是一个PUT请求,而不是POST。

删除一个资源(HTTP DELETE)

现在,你可能已经能预测到如何发送一个DELETE请求了:

// Delete a product 
// 删除一个产品
response = client.DeleteAsync(gizmoUri).Result; 
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);

与GET一样,DELETE请求没有请求体,因此你不必指定JSON或XML格式。

错误处理

HttpClient在它接收到一个带有错误代码的HTTP响应时,不会抛出异常。但是,该响应的StatusCode属性含有状态码。而且,如果其状态是一个成功的状态码(状态码在200-299之间)时,IsSuccessStatusCode属性为true。

使用这种模式的前面这个例子为:

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

如果你喜欢把错误代码处理成异常,可以调用EnsureSuccessStatusCode方法。这个方法在响应状态不是一个成功的代码时,会抛出一个异常。

try 
{ 
    var resp = client.GetAsync("api/products").Result; 
    resp.EnsureSuccessStatusCode();    // Throw if not a success code. 

    // ... 
} 
catch (HttpRequestException e) 
{ 
    Console.WriteLine(e.Message); 
}

当然,由于其它原因,HttpClient也可能抛出异常 — 例如,请求超时的时候。

配置HttpClient

为了配置HttpClient,可以创建一个WebRequestHandler实例,设置其属性,并把它传递给HttpClient构造器:

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

WebRequestHandler派生于HttpMessageHandler。通过从HttpMessageHandler派生,你也可以插入自定义消息处理程序。更多信息参阅“HTTP消息处理器(本系列教程的第5.1小节 — 译者注)”。

其它资源


控制台应用程序使我们很容易看到代码流程。然而,阻塞调用对于图形UI的应用程序并不是一种好的做法。要了解如何处理非阻塞HttpClient中的异步操作,参阅“通过WPF应用程序调用Web API”(本系列教程的第3.3小节 — 译者注)。

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值