daily_digest/Services/OpenWeatherMapService.cs
2025-04-12 00:27:03 +07:00

108 lines
5.1 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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