daily_digest/Services/OpenWeatherMapService.cs

108 lines
5.1 KiB
C#
Raw Normal View History

using DailyDigestWorker.Configuration; // Для DataSourceUrls, ApiKeys
using DailyDigestWorker.Models; // Для WeatherData
using DailyDigestWorker.Models.OpenWeatherMap; // Для DTO классов
using Microsoft.Extensions.Options; // Для IOptions
using Newtonsoft.Json; // Для JsonConvert
namespace DailyDigestWorker.Services
{
public class OpenWeatherMapService : IWeatherService // Реализуем интерфейс
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<OpenWeatherMapService> _logger;
private readonly DataSourceUrls _dataSourceUrls;
private readonly ApiKeys _apiKeys;
// Внедряем зависимости, включая ApiKeys
public OpenWeatherMapService(
IHttpClientFactory httpClientFactory,
IOptions<DataSourceUrls> dataSourceUrlsOptions,
IOptions<ApiKeys> apiKeysOptions, // Добавляем ApiKeys
ILogger<OpenWeatherMapService> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
_dataSourceUrls = dataSourceUrlsOptions.Value;
_apiKeys = apiKeysOptions.Value; // Сохраняем ApiKeys
}
public async Task<WeatherData?> GetWeatherAsync(CancellationToken cancellationToken)
{
// Проверяем наличие ключа API
if (string.IsNullOrWhiteSpace(_apiKeys.OpenWeatherMap))
{
_logger.LogError("Ключ API для OpenWeatherMap не сконфигурирован.");
return null;
}
// Формируем URL, подставляя API ключ
string requestUrl = string.Format(_dataSourceUrls.OpenWeatherMap, _apiKeys.OpenWeatherMap);
_logger.LogInformation("Запрос погоды с OpenWeatherMap: {Url}", requestUrl);
var client = _httpClientFactory.CreateClient();
try
{
HttpResponseMessage response = await client.GetAsync(requestUrl, cancellationToken);
if (!response.IsSuccessStatusCode)
{
_logger.LogError("Ошибка при запросе к API OpenWeatherMap. Статус код: {StatusCode}", response.StatusCode);
// Попробуем прочитать тело ошибки, если есть
string errorBody = await response.Content.ReadAsStringAsync(cancellationToken);
_logger.LogError("Тело ошибки OpenWeatherMap: {ErrorBody}", errorBody);
return null;
}
string jsonResponse = await response.Content.ReadAsStringAsync(cancellationToken);
// Десериализуем JSON в наш DTO
var weatherResponseDto = JsonConvert.DeserializeObject<WeatherResponseDto>(jsonResponse);
// Проверяем основные данные
if (weatherResponseDto?.Main == null || weatherResponseDto.Weather == null || !weatherResponseDto.Weather.Any())
{
_logger.LogWarning("Не удалось десериализовать основные данные из ответа OpenWeatherMap или они пусты.");
return null;
}
// Извлекаем нужную информацию
var mainData = weatherResponseDto.Main;
var descriptionData = weatherResponseDto.Weather.First(); // Берем первое описание
_logger.LogInformation("Погода успешно получена: {Description}, {Temperature}°C", descriptionData.Description, mainData.Temp);
// Создаем и возвращаем нашу модель WeatherData
var resultData = new WeatherData
{
TemperatureC = mainData.Temp,
FeelsLikeC = mainData.FeelsLike,
Description = descriptionData.Description ?? "Нет данных", // Используем ?? для значения по умолчанию
Icon = descriptionData.Icon ?? ""
};
return resultData;
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "Ошибка HTTP при запросе к API OpenWeatherMap.");
return null;
}
catch (JsonException ex)
{
_logger.LogError(ex, "Ошибка парсинга JSON ответа OpenWeatherMap.");
return null;
}
catch (OperationCanceledException)
{
_logger.LogInformation("Запрос погоды был отменен.");
return null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Неожиданная ошибка при получении погоды OpenWeatherMap.");
return null;
}
}
}
}