Files
DocumentService/DocumentService.Client/Clients/BaseDocumentClient.cs

180 lines
6.4 KiB
C#

using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
namespace DocumentService.Client.Clients;
/// <summary>
/// Base class for all DocumentService HTTP clients.
/// Provides common HTTP operations and error handling.
/// </summary>
/// <remarks>
///
/// </remarks>
/// <param name="HttpClient"></param>
/// <param name="logger"></param>
/// <exception cref="ArgumentNullException"></exception>
public abstract class BaseDocumentClient(HttpClient HttpClient, ILogger logger)
{
/// <summary>
///
/// </summary>
protected readonly ILogger Logger = logger ?? throw new ArgumentNullException(nameof(logger));
/// <summary>
/// Sends a multipart/form-data POST with a single file and deserializes the JSON response.
/// </summary>
protected async Task<TResponse?> SendMultipartAsync<TResponse>(
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<TResponse>(cancellationToken);
}
/// <summary>
/// Sends a multipart/form-data POST with a single file and returns the response as a stream.
/// </summary>
protected async Task<Stream> 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
}
/// <summary>
/// Sends a multipart/form-data POST with a single file and returns the raw byte array.
/// </summary>
protected async Task<byte[]> 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
}
/// <summary>
/// Sends a caller-built <see cref="MultipartFormDataContent"/> and returns the response as a stream.
/// Use this overload when the multipart body contains more than one file (e.g., merge).
/// </summary>
protected async Task<Stream> 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
}
/// <summary>
/// Serializes <paramref name="request"/> as JSON, POSTs it, and deserializes the response.
/// </summary>
protected async Task<TResponse?> SendJsonAsync<TRequest, TResponse>(
string endpoint,
TRequest request,
CancellationToken cancellationToken = default)
{
var response = await HttpClient.PostAsJsonAsync(endpoint, request, cancellationToken);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<TResponse>(cancellationToken);
}
/// <summary>
/// Serializes <paramref name="request"/> as JSON, POSTs it, and returns the response as a stream.
/// </summary>
protected async Task<Stream> SendJsonForStreamAsync<TRequest>(
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
}
/// <summary>
/// Serializes <paramref name="request"/> as JSON, POSTs it, and returns the raw byte array.
/// </summary>
protected async Task<byte[]> SendJsonForBinaryAsync<TRequest>(
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
}
/// <summary>Converts a byte array to a Base64 string.</summary>
protected static string ToBase64(byte[] bytes) => Convert.ToBase64String(bytes);
/// <summary>Reads a stream fully into a byte array.</summary>
protected static async Task<byte[]> 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();
}
}