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