Kết hợp Rx.NET và Json.NET để gọi REST API

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

Thẻ: Rx.NET Json.NET REST API C# HttpClient

Đăng vào ngày 12 tháng 7 lúc 06:02