Example flow:
Current implementation:
public async Task EmbedIdAndSendAsync(string filePath, string id, HttpClient httpClient)
{
using (Stream stream = File.OpenRead(filePath))
using (PdfDocument pdf = new PdfDocument(stream))
using (MemoryStream modifiedStream = new MemoryStream())
{
pdf.EmbedId(id);
pdf.WriteTo(modifiedStream);
modifiedStream.Position = 0;
await httpClient.PostAsync(
"files/upload",
new MultipartFormDataContent {
{ new StringContent(id), "file[id]" },
{ new StreamContent(modifiedStream), "file[stream]", Path.GetFileName(filePath) }
}
);
}
}
How would I write file modifications directly to HttpClient's network stream without having to use an intermediary memory stream?
The answer is you have to define your own HttpContent
.
In this way you kinda invert the task and HttpClient
will call your code when needed and only if needed (because maybe there's no network connection or any other error)
sealed class PdfContent : HttpContent
{
string filePath;
string id;
public PdfContent(string filePath, string id)
{
this.filePath = filePath;
this.id = id;
// Put something here to define content or just do it in the outer code
Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken)
{
// Here you can write to a stream directly
using Stream fileStream = File.OpenRead(filePath);
using PdfDocument pdf = new PdfDocument(fileStream);
pdf.EmbedId(id);
// Use async + cancellationToken if there's one
pdf.WriteTo(stream);
return Task.CompletedTask;
}
// This is just a technical compatibility override to support cancellation
protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context)
{
return SerializeToStreamAsync(stream, context, CancellationToken.None);
}
protected override bool TryComputeLength(out long length)
{
// Return something if you know length or zero if not
length = 0;
return false;
}
}
Now just post it.
await httpClient.PostAsync(
"files/upload",
new MultipartFormDataContent {
{ new StringContent(id), "file[id]" },
{ new PdfContent(filePath, id), "file[stream]" }
}
);