Giới thiệu JSON : Placeholder
JSON : Placeholder là dịch vụ REST API thử nghiệm phổ biến. Bài viết minh họa cách gọi các endpoint sau:
- GET /posts/1
- GET /posts
- POST /posts
- PUT /posts/1
- DELETE /posts/1
Tất cả endpoint GET trả về dữ liệu JSON có cấu trúc:
{
"type": "object",
"properties": {
"userId": {"type": "integer"},
"id": {"type": "integer"},
"title": {"type": "string"},
"body": {"type": "string"}
}
}
Lớp Post
Định nghĩa lớp ánh xạ JSON với .NET:
public class Post
{
[JsonProperty("userId")]
public int UserId { get; set; }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("body")]
public string Body { get; set; }
public override string ToString() =>
$"Post {{userId={UserId}, id={Id}, title=\"{Title}\", body=\"{Body.Replace("\n", "\\n")}\"}}";
}
Triển khai với Task API
public class PostTaskService
{
private readonly HttpClient _client = new HttpClient
{
BaseAddress = new Uri("https://jsonplaceholder.typicode.com/")
};
public async Task<string> FetchPostAsStringAsync(int id)
{
if (!CrossConnectivity.Current.IsConnected) return null;
return await _client.GetStringAsync($"posts/{id}");
}
public async Task<Post> FetchPostAsJsonAsync(int id)
{
if (!CrossConnectivity.Current.IsConnected) return null;
var json = await _client.GetStringAsync($"posts/{id}");
return JsonConvert.DeserializeObject<Post>(json);
}
public async Task FetchTopPostsAsync(int count)
{
if (!CrossConnectivity.Current.IsConnected) return new List<Post>();
var json = await _client.GetStringAsync("posts");
var posts = JsonConvert.DeserializeObject(json);
return posts.Take(count).ToList();
}
private StringContent CreateJsonContent(Post post) =>
new StringContent(JsonConvert.SerializeObject(post), Encoding.UTF8, "application/json");
public async Task<Post> CreatePostAsync(Post post)
{
if (post == null || !CrossConnectivity.Current.IsConnected) return null;
var response = await _client.PostAsync("posts", CreateJsonContent(post));
if (!response.IsSuccessStatusCode) return null;
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Post>(json);
}
public async Task<Post> UpdatePostAsync(Post post)
{
if (post == null || !CrossConnectivity.Current.IsConnected) return null;
var response = await _client.PutAsync($"posts/{post.Id}", CreateJsonContent(post));
if (!response.IsSuccessStatusCode) return null;
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Post>(json);
}
public async Task<string> DeletePostAsync(int id)
{
if (!CrossConnectivity.Current.IsConnected) return null;
var response = await _client.DeleteAsync($"posts/{id}");
if (!response.IsSuccessStatusCode) return null;
return await response.Content.ReadAsStringAsync();
}
}
Triển khai với Rx.NET
public class PostReactiveService
{
private readonly HttpClient _client = new HttpClient
{
BaseAddress = new Uri("https://jsonplaceholder.typicode.com/")
};
public IObservable<string> FetchPostAsStringAsync(int id) =>
CrossConnectivity.Current.IsConnected
? _client.GetStringAsync($"posts/{id}").ToObservable()
: Observable.Empty<string>();
public IObservable<Post> FetchPostAsJsonStream(int id) =>
CrossConnectivity.Current.IsConnected
? _client.GetStringAsync($"posts/{id}")
.ToObservable()
.Select(json => JsonConvert.DeserializeObject<Post>(json))
: Observable.Empty<Post>();
public IObservable<Post> FetchTopPostsStream(int count) =>
CrossConnectivity.Current.IsConnected
? _client.GetStringAsync("posts")
.ToObservable()
.SelectMany(json => JsonConvert.DeserializeObject(json))
.Take(count)
: Observable.Empty<Post>();
private StringContent CreateJsonContent(Post post) =>
new StringContent(JsonConvert.SerializeObject(post), Encoding.UTF8, "application/json");
public IObservable<Post> CreatePostStream(Post post) =>
post == null || !CrossConnectivity.Current.IsConnected
? Observable.Empty<Post>()
: _client.PostAsync("posts", CreateJsonContent(post))
.ToObservable()
.SelectMany(response =>
response.IsSuccessStatusCode
? response.Content.ReadAsStringAsync().ToObservable()
.Select(json => JsonConvert.DeserializeObject<Post>(json))
: Observable.Empty<Post>());
public IObservable<Post> UpdatePostStream(Post post) =>
post == null || !CrossConnectivity.Current.IsConnected
? Observable.Empty<Post>()
: _client.PutAsync($"posts/{post.Id}", CreateJsonContent(post))
.ToObservable()
.SelectMany(response =>
response.IsSuccessStatusCode
? response.Content.ReadAsStringAsync().ToObservable()
.Select(json => JsonConvert.DeserializeObject<Post>(json))
: Observable.Empty<Post>());
public IObservable<string> DeletePostStream(int id) =>
CrossConnectivity.Current.IsConnected
? _client.DeleteAsync($"posts/{id}")
.ToObservable()
.SelectMany(response =>
response.IsSuccessStatusCode
? response.Content.ReadAsStringAsync().ToObservable()
: Observable.Empty<string>())
: Observable.Empty<string>();
}
Hàm Main minh họa
public static void Main()
{
// Sử dụng Task API
var taskService = new PostTaskService();
Console.WriteLine(taskService.FetchPostAsStringAsync(1).Result);
Console.WriteLine(taskService.FetchPostAsJsonAsync(1).Result);
foreach (var post in taskService.FetchTopPostsAsync(2).Result)
{
Console.WriteLine(post);
}
// Sử dụng Rx.NET
var rxService = new PostReactiveService();
rxService.FetchPostAsStringAsync(1).Subscribe(Console.WriteLine);
rxService.FetchPostAsJsonStream(1).Subscribe(Console.WriteLine);
rxService.FetchTopPostsStream(2).Subscribe(Console.WriteLine);
Console.ReadKey();
}
Kết quả đầu ra
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Post {userId=1, id=1, title="sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body="quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}