基本用法
本指南涵盖使用 RestClient.Net 进行 REST 调用的基础知识。
第一个请求
让我们发起一个简单的 GET 请求来获取帖子:
using System.Net.Http.Json;
using RestClient.Net;
using Urls;
// 定义模型
record Post(int UserId, int Id, string Title, string Body);
record ErrorResponse(string Message);
// 创建 HttpClient(在生产环境中使用 IHttpClientFactory)
using var httpClient = new HttpClient();
// 发起请求
var result = await httpClient.GetAsync(
url: "https://jsonplaceholder.typicode.com/posts/1".ToAbsoluteUrl(),
deserializeSuccess: async (content, ct) =>
await content.ReadFromJsonAsync<Post>(ct)
?? throw new InvalidOperationException("空响应"),
deserializeError: async (content, ct) =>
await content.ReadFromJsonAsync<ErrorResponse>(ct)
?? new ErrorResponse("未知错误")
);
// 处理结果 - 必须处理所有情况
var message = result switch
{
Outcome.Result<Post, Outcome.HttpError<ErrorResponse>>.Ok(var post) =>
$"成功: {post.Title}",
Outcome.Result<Post, Outcome.HttpError<ErrorResponse>>.Error(
Outcome.HttpError<ErrorResponse>.ResponseError(var err, var status, _)) =>
$"API 错误 {status}: {err.Message}",
Outcome.Result<Post, Outcome.HttpError<ErrorResponse>>.Error(
Outcome.HttpError<ErrorResponse>.ExceptionError(var ex)) =>
$"异常: {ex.Message}",
};
Console.WriteLine(message);
使用类型别名
完整类型名称很冗长。在 GlobalUsings.cs 中添加类型别名:
// GlobalUsings.cs
global using OkPost = Outcome.Result<Post, Outcome.HttpError<ErrorResponse>>
.Ok<Post, Outcome.HttpError<ErrorResponse>>;
global using ErrorPost = Outcome.Result<Post, Outcome.HttpError<ErrorResponse>>
.Error<Post, Outcome.HttpError<ErrorResponse>>;
global using ResponseErrorPost = Outcome.HttpError<ErrorResponse>.ErrorResponseError;
global using ExceptionErrorPost = Outcome.HttpError<ErrorResponse>.ExceptionError;
现在模式匹配更简洁了:
var message = result switch
{
OkPost(var post) => $"成功: {post.Title}",
ErrorPost(ResponseErrorPost(var err, var status, _)) => $"API 错误 {status}: {err.Message}",
ErrorPost(ExceptionErrorPost(var ex)) => $"异常: {ex.Message}",
};
POST 请求
使用 POST 创建新资源:
record CreatePostRequest(string Title, string Body, int UserId);
var newPost = new CreatePostRequest("我的标题", "我的内容", 1);
var result = await httpClient.PostAsync(
url: "https://jsonplaceholder.typicode.com/posts".ToAbsoluteUrl(),
body: newPost,
serializeRequest: body => JsonContent.Create(body),
deserializeSuccess: async (content, ct) =>
await content.ReadFromJsonAsync<Post>(ct)
?? throw new InvalidOperationException("空响应"),
deserializeError: async (content, ct) =>
await content.ReadFromJsonAsync<ErrorResponse>(ct)
?? new ErrorResponse("未知错误")
);
PUT 请求
替换现有资源:
record UpdatePostRequest(int Id, string Title, string Body, int UserId);
var updatedPost = new UpdatePostRequest(1, "更新的标题", "更新的内容", 1);
var result = await httpClient.PutAsync(
url: "https://jsonplaceholder.typicode.com/posts/1".ToAbsoluteUrl(),
body: updatedPost,
serializeRequest: body => JsonContent.Create(body),
deserializeSuccess: async (content, ct) =>
await content.ReadFromJsonAsync<Post>(ct)
?? throw new InvalidOperationException("空响应"),
deserializeError: async (content, ct) =>
await content.ReadFromJsonAsync<ErrorResponse>(ct)
?? new ErrorResponse("未知错误")
);
DELETE 请求
删除资源:
record DeleteResponse(bool Success);
var result = await httpClient.DeleteAsync(
url: "https://jsonplaceholder.typicode.com/posts/1".ToAbsoluteUrl(),
deserializeSuccess: async (content, ct) =>
new DeleteResponse(true),
deserializeError: async (content, ct) =>
await content.ReadFromJsonAsync<ErrorResponse>(ct)
?? new ErrorResponse("未知错误")
);
PATCH 请求
部分更新资源:
record PatchPostRequest(string? Title = null, string? Body = null);
var patch = new PatchPostRequest(Title: "只更新标题");
var result = await httpClient.PatchAsync(
url: "https://jsonplaceholder.typicode.com/posts/1".ToAbsoluteUrl(),
body: patch,
serializeRequest: body => JsonContent.Create(body),
deserializeSuccess: async (content, ct) =>
await content.ReadFromJsonAsync<Post>(ct)
?? throw new InvalidOperationException("空响应"),
deserializeError: async (content, ct) =>
await content.ReadFromJsonAsync<ErrorResponse>(ct)
?? new ErrorResponse("未知错误")
);
可复用的反序列化器
创建可复用的反序列化器方法:
public static class Deserializers
{
public static async Task<T> Json<T>(HttpContent content, CancellationToken ct)
where T : class =>
await content.ReadFromJsonAsync<T>(ct)
?? throw new InvalidOperationException($"反序列化 {typeof(T).Name} 失败");
public static async Task<ErrorResponse> Error(HttpContent content, CancellationToken ct) =>
await content.ReadFromJsonAsync<ErrorResponse>(ct)
?? new ErrorResponse("未知错误");
}
// 使用方式
var result = await httpClient.GetAsync(
url: "https://api.example.com/posts/1".ToAbsoluteUrl(),
deserializeSuccess: Deserializers.Json<Post>,
deserializeError: Deserializers.Error
);
添加请求头
在 HttpClient 上设置请求头:
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "your-token");
httpClient.DefaultRequestHeaders.Add("X-Custom-Header", "value");
var result = await httpClient.GetAsync(...);
查询参数
使用查询参数构建 URL:
// 使用字符串插值
var url = $"https://api.example.com/posts?userId={userId}&page={page}".ToAbsoluteUrl();
// 或使用 URL 构建库
var result = await httpClient.GetAsync(
url: url,
deserializeSuccess: Deserializers.Json<List<Post>>,
deserializeError: Deserializers.Error
);
取消操作
传递 CancellationToken 以支持可取消的请求:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var result = await httpClient.GetAsync(
url: "https://api.example.com/posts/1".ToAbsoluteUrl(),
deserializeSuccess: Deserializers.Json<Post>,
deserializeError: Deserializers.Error,
cancellationToken: cts.Token
);
最佳实践
- 在生产环境中使用 IHttpClientFactory 以实现正确的连接池管理
- 在 GlobalUsings.cs 中定义类型别名 以保持代码简洁
- 创建可复用的反序列化器 以避免重复
- 始终处理所有情况 在 switch 表达式中
- 使用取消令牌 用于面向用户的请求