Files
MilkyShots/MilkStream.Client/Services/ServiceBase.cs
T

69 lines
2.6 KiB
C#

using System.Text.Json;
using Microsoft.Extensions.Options;
namespace MilkStream.Client.Services;
/// <summary>
/// Configuration options for service base URL.
/// </summary>
public class ServiceOptions {
/// <summary>
/// Gets or sets the base URL for API requests.
/// </summary>
public string BaseUrl { get; set; } = string.Empty;
}
/// <summary>
/// Abstract class for services that require an HTTP client.
/// </summary>
public abstract class ServiceBase {
/// <summary>
/// Provided client for making HTTP requests.
/// </summary>
protected virtual HttpClient Client { get; init; }
/// <summary>
/// Gets the logger instance.
/// </summary>
protected virtual ILogger Logger { get; init; }
/// <summary>
/// Initializes a new instance of the <see cref="ServiceBase"/> class with the specified options and HTTP client factory.
/// </summary>
/// <param name="options"></param>
/// <param name="httpClientFactory"></param>
/// <param name="logger"></param>
protected ServiceBase(IOptions<ServiceOptions> options, IHttpClientFactory httpClientFactory, ILogger logger) {
Logger = logger;
Client = httpClientFactory.CreateClient();
Client.BaseAddress = new Uri(options.Value.BaseUrl);
Client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")
);
}
/// <summary>
/// Sends a GET request and deserializes the JSON response body.
/// Standard read contract for API services: any failure — non-success status code,
/// network error, or malformed body — yields <c>null</c> (default for value types)
/// and is logged as a warning. This method never throws.
/// </summary>
/// <typeparam name="T">The DTO type to deserialize the response body into.</typeparam>
/// <param name="url">The request URL, relative to the API base address.</param>
/// <returns>The deserialized response, or a default value when the request failed.</returns>
protected async Task<T?> GetJsonAsync<T>(string url) {
try {
var response = await Client.GetAsync(url);
if (!response.IsSuccessStatusCode) {
Logger.LogWarning("GET {Url} failed with status {StatusCode}", url, (int)response.StatusCode);
return default;
}
return await response.Content.ReadFromJsonAsync<T>();
} catch (Exception ex) when (ex is HttpRequestException or JsonException or NotSupportedException) {
Logger.LogWarning(ex, "GET {Url} failed", url);
return default;
}
}
}