使异步任务变得通用

问题描述 投票:0回答:1

我正在开发一个内部控制台应用程序,该应用程序允许用户从我们的分页 JSON API 获取全套结果。我们有许多不同的类型,但都属于相同的基本结构。

public class Tickets
{
    public Ticket[] tickets { get; set; }
    public string nextPageURL { get; set; }
    public string previousPageURL { get; set; }
    public int recordCount { get; set; }
}

public class Ticket
{
 ...
}

我有一个异步任务来进行调用并循环分页结果并将结果发送到单个 JSON 文件中。但我想让它变得通用,而不是本质上相同的代码重复 17 次,每种类型一个。

我当前的代码是:

    private static async Task<List<Ticket>> GetTicketsAsync(Action<Tickets> callBack = null)
    {
        var tickets = new List<Ticket>();
        HttpClient httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Basic", 
            Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes($"-----")));
        httpClient.BaseAddress = new Uri("-----");
        var nextUrl = "/api/tickets";
        
        do
        {
            await httpClient.GetAsync(nextUrl)
                .ContinueWith(async (ticketSearchTask) =>
                {
                    var response = await ticketSearchTask;
                    if (response.IsSuccessStatusCode)
                    {
                        string jsonString = await response.Content.ReadAsStringAsync();
                        try
                        {
                            var result = JsonSerializer.Deserialize<Tickets>(jsonString);
                            if (result != null)
                            {
                                // Build the full list to return later after the loop.
                                if (result.tickets.Any())
                                    tickets.AddRange(result.tickets.ToList());

                                // Run the callback method, passing the current page of data from the API.
                                if (callBack != null)
                                    callBack(result);

                                // Get the URL for the next page
                                nextUrl = (result.nextPageURL != null) ? result.nextPageURL : string.Empty;
                            }
                        } catch (Exception ex)
                        {
                            Console.WriteLine($"\n We ran into an error: {ex.Message}");
                            nextUrl = string.Empty;
                        }
                       
                    }
                    else
                    {
                        // End loop if we get an error response.
                        nextUrl = string.Empty;
                    }
                });

        } while (!string.IsNullOrEmpty(nextUrl));
        return tickets;
    }

    private static void TicketsCallBack(Tickets tickets)
    {
        if (tickets != null && tickets.count > 0)
        {
            foreach (var ticket in tickets.tickets)
            {
                Console.WriteLine($"fetched ticket: {ticket.id}");
            }
        }
    }

我已经开始使用通用方法,但引用第二级(在他的实例中为票据对象)给我带来了问题以及获取 nextPageURL。保留回调结构以保持控制台随着已处理的数据滴答作响也很好。

    private static async Task<List<T>> GetAsync<T>(string type, Action<T> callBack = null, string ticketId = null)
    {
        var results = new List<T>();
        HttpClient httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Basic",
            Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes($"-----")));
        httpClient.BaseAddress = new Uri("-----");
        var nextUrl = $"/api/{type}.json";

        do
        {
            await httpClient.GetAsync(nextUrl)
                .ContinueWith(async (searchTask) =>
                {
                    var response = await searchTask;
                    if (response.IsSuccessStatusCode)
                    {
                        string jsonString = await response.Content.ReadAsStringAsync();
                        try
                        {
                            var result = JsonSerializer.Deserialize<T>(jsonString);
                            if (result != null)
                            {
                                // Build the full list to return later after the loop.
                                if (result.tickets.Any())
                                     results.AddRange(result.tickets.ToList());

                                // Run the callback method, passing the current page of data from the API.
                                if (callBack != null)
                                    callBack(result);

                                // Get the URL for the next page
                                nextUrl = (result.GetType().GetProperty("nextPageURL") != null) ? result.GetType().GetProperty("nextPageURL").ToString() : string.Empty;
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"\nWe ran into an error: {ex.Message}");
                            nextUrl = string.Empty;
                        }


                    }
                    else
                    {
                        // End loop if we get an error response.
                        nextUrl = string.Empty;
                    }
                });

        } while (!string.IsNullOrEmpty(nextUrl));
        return results;
    }

非常感谢任何帮助。

c# json console-application
1个回答
0
投票

首先,如果您有多个遵循相同结构的对象,您可能会使其通用:

public class Paged<T>
{
    T[] Data { get;  set;}
    string nextPageURL { get;  set;}
    string previousPageURL { get; set;}
    int recordCount { get; set; }
}

您应该能够或多或少地使用它来代替门票对象:

private static async Task<List<T>> GetAsync<T>(string type, Action<Paged<T>> callBack = null)
    ...
    var result = JsonSerializer.Deserialize<Paged<T>>(jsonString);

如果由于向后兼容性而无法使用通用类型,您仍然可以为所有类似的类创建通用接口:

public interface IPaged<T>
{
    public T[] Data{ get;}
    public string nextPageURL { get; set; }
    public string previousPageURL { get; set; }
    public int recordCount { get; set; }
}
public class Tickets : IPaged<Ticket>
{
    public Ticket[] Data => tickets;
    public Ticket[] tickets { get; set; }
    public string nextPageURL { get; set; }
    public string previousPageURL { get; set; }
    public int recordCount { get; set; }
}

private static async Task<List<TData>> GetAsync<T, TData>(string type, Action<T> callBack = null) where T : IPaged<TData>
{
...
     var result = JsonSerializer.Deserialize<T>(jsonString);
...
}
var allTickets = await GetAsync<Tickets, Ticket>(...);

但是,我会考虑使用 IAsyncEnumerable 接口,例如:

private static async IAsyncEnumerable<T[]> GetAsync<T>(string type){
   ...
   var result = JsonSerializer.Deserialize<Paged<T>>(jsonString);
   if (result != null)
   {
        yield return result.Data;
   }
   ...

这应该在获取数据的代码和处理数据的代码之间提供更清晰的分离。

© www.soinside.com 2019 - 2024. All rights reserved.