using Microsoft.Extensions.Logging; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Http.Json; namespace DocumentService.Client.Clients; /// /// Base class for all DocumentService HTTP clients. /// Provides common HTTP operations and error handling. /// /// /// /// /// /// /// public abstract class BaseDocumentClient(HttpClient HttpClient, ILogger logger) { /// /// /// protected readonly ILogger Logger = logger ?? throw new ArgumentNullException(nameof(logger)); /// /// Sends a multipart/form-data POST with a single file and deserializes the JSON response. /// protected async Task SendMultipartAsync( string endpoint, Stream fileStream, string fileName = "file.pdf", CancellationToken cancellationToken = default) { using var content = new MultipartFormDataContent(); var streamContent = new StreamContent(fileStream); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); content.Add(streamContent, "file", fileName); var response = await HttpClient.PostAsync(endpoint, content, cancellationToken); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(cancellationToken); } /// /// Sends a multipart/form-data POST with a single file and returns the response as a stream. /// protected async Task SendMultipartForStreamAsync( string endpoint, Stream fileStream, string fileName = "file.pdf", CancellationToken cancellationToken = default) { using var content = new MultipartFormDataContent(); var streamContent = new StreamContent(fileStream); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); content.Add(streamContent, "file", fileName); var response = await HttpClient.PostAsync(endpoint, content, cancellationToken); response.EnsureSuccessStatusCode(); #if NETFRAMEWORK return await response.Content.ReadAsStreamAsync(); #else return await response.Content.ReadAsStreamAsync(cancellationToken); #endif } /// /// Sends a multipart/form-data POST with a single file and returns the raw byte array. /// protected async Task SendMultipartForBinaryAsync( string endpoint, Stream fileStream, string fileName = "file.pdf", CancellationToken cancellationToken = default) { using var content = new MultipartFormDataContent(); var streamContent = new StreamContent(fileStream); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); content.Add(streamContent, "file", fileName); var response = await HttpClient.PostAsync(endpoint, content, cancellationToken); response.EnsureSuccessStatusCode(); #if NETFRAMEWORK return await response.Content.ReadAsByteArrayAsync(); #else return await response.Content.ReadAsByteArrayAsync(cancellationToken); #endif } /// /// Sends a caller-built and returns the response as a stream. /// Use this overload when the multipart body contains more than one file (e.g., merge). /// protected async Task SendMultipartContentForStreamAsync( string endpoint, MultipartFormDataContent content, CancellationToken cancellationToken = default) { var response = await HttpClient.PostAsync(endpoint, content, cancellationToken); response.EnsureSuccessStatusCode(); #if NETFRAMEWORK return await response.Content.ReadAsStreamAsync(); #else return await response.Content.ReadAsStreamAsync(cancellationToken); #endif } /// /// Serializes as JSON, POSTs it, and deserializes the response. /// protected async Task SendJsonAsync( string endpoint, TRequest request, CancellationToken cancellationToken = default) { var response = await HttpClient.PostAsJsonAsync(endpoint, request, cancellationToken); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(cancellationToken); } /// /// Serializes as JSON, POSTs it, and returns the response as a stream. /// protected async Task SendJsonForStreamAsync( string endpoint, TRequest request, CancellationToken cancellationToken = default) { var response = await HttpClient.PostAsJsonAsync(endpoint, request, cancellationToken); response.EnsureSuccessStatusCode(); #if NETFRAMEWORK return await response.Content.ReadAsStreamAsync(); #else return await response.Content.ReadAsStreamAsync(cancellationToken); #endif } /// /// Serializes as JSON, POSTs it, and returns the raw byte array. /// protected async Task SendJsonForBinaryAsync( string endpoint, TRequest request, CancellationToken cancellationToken = default) { var response = await HttpClient.PostAsJsonAsync(endpoint, request, cancellationToken); response.EnsureSuccessStatusCode(); #if NETFRAMEWORK return await response.Content.ReadAsByteArrayAsync(); #else return await response.Content.ReadAsByteArrayAsync(cancellationToken); #endif } /// Converts a byte array to a Base64 string. protected static string ToBase64(byte[] bytes) => Convert.ToBase64String(bytes); /// Reads a stream fully into a byte array. protected static async Task StreamToBytesAsync(Stream stream, CancellationToken cancellationToken = default) { if (stream is MemoryStream ms) return ms.ToArray(); using var memoryStream = new MemoryStream(); #if NET8_0 await stream.CopyToAsync(memoryStream, cancellationToken); #else await stream.CopyToAsync(memoryStream); #endif return memoryStream.ToArray(); } }