Как правильно синхронизировать приложение с «async» и «await»?

#c# #json #api #asynchronous

#c# #json #API #асинхронный

Вопрос:

 class Website
{
    public Website(string link)
    {
        _linkToWeb = new RestClient(link);
    }
    public async Task<string> DownloadAsync(string path)
    {
        var request = new RestRequest(path, Method.GET);
        var response = _linkToWeb.ExecuteAsync(request);
        return response.Result.Content;
    }
    public RestClient _linkToWeb { get; set; }
}

class Program
{
    public static Website API = new Website("https://api.collegefootballdata.com");
    public static async Task<string> _downloadTeamsFromAPI()
    {
        return API.Download("/teams/fbs");
    }
    public static async Task<string> _downloadAdvancedInfoFromAPI()
    {
        return API.Download("/stats/season/advanced?year=2010");
    }
    public static async Task<Teams> _addTeamToDB(Teams item)
    {
        var tmp = new Teams
        {
            School = item.School,
            Abbreviation = item.Abbreviation,
            Conference = item.Conference,
            Divison = item.Divison,
            Color = item.Color,
            Alt_Color = item.Alt_Color,
            Team = await _getAdvancedInfoFromAPI(item.Conference)
        };
        return tmp;
    }
    public static async Task<string> _getAdvancedInfoFromAPI(string _conferenceName)
    {
        List<Advanced> advancedDataList = new List<Advanced>();
        var advancedData = await _downloadAdvancedInfoFromAPI();
        var advancedDataDeserialized = JsonSerializer.Deserialize<Advanced[]>(advancedData, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });

        foreach (var item in advancedDataDeserialized)
        {
            advancedDataList.Add(new Advanced
            {
                Team =                  item.Team,
                //Conference =            item.Conference,
                Year =                  item.Year,
                excludeGarbageTime =    item.excludeGarbageTime,
                startWeek =             item.startWeek,
                endWeek =               item.endWeek
            });
        }
        return await _lookForMatch(_conferenceName, advancedDataList);
    }
    public static async Task<string> _lookForMatch(string _Confa, List<Advanced> lista)
    {
        return lista
                        .Where(x => x.Conference == _Confa)
                        .Select(x => x.Team)
                        .FirstOrDefault();
    }
    public static async Task Main()
    {
        Console.WriteLine("Odpaliłem program!n");
        using var db = new Context();
        db.Database.EnsureCreated();
        Console.WriteLine("Stworzylem baze!n");
        var teams = await _downloadTeamsFromAPI();

        var deserializer = JsonSerializer.Deserialize<Teams[]>(teams, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
        Console.WriteLine("Zdeserializowalem dane!n");
        foreach (var item in deserializer)
        {
            db.Teams.Add(await _addTeamToDB(item));
            Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
            Console.WriteLine("Dodalem element do bazy...n");
        };
        db.SaveChanges();
        Console.WriteLine("Zapisalem dane do bazy!");
    }
} 
  

Я знаю, что это вопрос новичка, но я не знаю, как заставить его работать :/

Я хочу сделать его немного асинхронным, потому что слова async и await точно не делают его более асинхронным, но я не знаю, как заставить его работать в любом случае асинхронно.

Приложение сначала загружает информацию из API, десериализует ее и сохраняет в переменной типа var. Затем он загружает расширенную информацию из API и присоединяется к ней с помощью элемента «Конференция». (это специально, даже если это не оптимально).

Существует множество async и await, но я не думаю, что это все равно выполняется асинхронно. Что я должен изменить, чтобы это приложение действительно было асинхронным?

Ответ №1:

Я ценю ваш мотив написать асинхронный код, чтобы сделать ваше приложение более масштабируемым. Однако, просмотрев опубликованный пример кода, я боюсь, что вам нужно больше изучить концепции асинхронного программирования, а не просто прыгать в консоль и пытаться написать какой-то код, который выглядит как асинхронный код.

Начните медленно и попытайтесь понять назначение Task библиотеки, когда ее использовать. Что await делает за кулисами. Когда обернуть возвращаемый тип с помощью Task и когда пометить метод как async . Это некоторые из основных ключевых слов, с которыми вы сталкиваетесь в асинхронном коде, и хорошее понимание их необходимо для написания / понимания асинхронного кода.

В Интернете доступно множество ресурсов, позволяющих разобраться в этих концепциях. Для начала вы можете начать изучать документацию Microsoft

Сказав это, inline — это переписывание примера кода с правильным использованием async/await . Пожалуйста, используйте это только для ссылок. Не пытайтесь вводить какой-либо производственный код до тех пор, пока у вас не будет хорошего понимания концепции.

Предоставляются необходимые комментарии для объяснения некоторых внесенных критических изменений.

 class Website
{
    public Website(string link)
    {
        _linkToWeb = new RestClient(link);
    }

    public async Task<string> DownloadAsync(string path)
    {
        var request = new RestRequest(path, Method.GET);
        var response = await _linkToWeb.ExecuteAsync(request); //await an asynchronous call.
        return response.Content; //No need to call response.Result. response content can be fetched after successful completion of asynchronous call.
    }
    public RestClient _linkToWeb { get; set; }
}

class Program
{
    public static Website API = new Website("https://api.collegefootballdata.com");

    public static async Task<string> _downloadTeamsFromAPI()
    {
        return await API.DownloadAsync("/teams/fbs");
    }

    public static async Task<string> _downloadAdvancedInfoFromAPI()
    {
        return await API.DownloadAsync("/stats/season/advanced?year=2010");
    }

    public static async Task<Teams> _addTeamToDB(Teams item)
    {
        var tmp = new Teams
        {
            School = item.School,
            Abbreviation = item.Abbreviation,
            Conference = item.Conference,
            Divison = item.Divison,
            Color = item.Color,
            Alt_Color = item.Alt_Color,
            Team = await _getAdvancedInfoFromAPI(item.Conference)
        };
        return tmp;
    }

    //Return type has to be Task<Teams> rather than Task<string> because the return object is Teams.
    public static async Task<Teams> _getAdvancedInfoFromAPI(string _conferenceName)
    {
        List<Advanced> advancedDataList = new List<Advanced>();
        var advancedData = await _downloadAdvancedInfoFromAPI();
        var advancedDataDeserialized = JsonSerializer.Deserialize<Advanced[]>(advancedData, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });

        foreach (var item in advancedDataDeserialized)
        {
            advancedDataList.Add(new Advanced
            {
                Team = item.Team,
                //Conference =            item.Conference,
                Year = item.Year,
                excludeGarbageTime = item.excludeGarbageTime,
                startWeek = item.startWeek,
                endWeek = item.endWeek
            });
        }
        return _lookForMatch(_conferenceName, advancedDataList);
    }

    //Return type is Teams and not string. 
    //Moreover Task<string> not required because we are not awaiting method call in this method.
    public static Teams _lookForMatch(string _Confa, List<Advanced> lista) 
    {
        return lista.Where(x => x.Conference == _Confa)
                        .Select(x => x.Team)
                        .FirstOrDefault();
    }

    public static async Task Main()
    {
        Console.WriteLine("Odpaliłem program!n");
        using var db = new Context();
        db.Database.EnsureCreated();
        Console.WriteLine("Stworzylem baze!n");
        var teams = await _downloadTeamsFromAPI();

        var deserializer = JsonSerializer.Deserialize<Teams[]>(teams, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
        Console.WriteLine("Zdeserializowalem dane!n");
        foreach (var item in deserializer)
        {
            db.Teams.Add(await _addTeamToDB(item));
            Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
            Console.WriteLine("Dodalem element do bazy...n");
        };
        db.SaveChanges();
        Console.WriteLine("Zapisalem dane do bazy!");
    }
}