feat: Add specialized client implementations for PDF operations
This commit is contained in:
179
DocumentService.Client/Clients/BaseDocumentClient.cs
Normal file
179
DocumentService.Client/Clients/BaseDocumentClient.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user