69 lines
2.6 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|