diff --git a/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs b/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs
index d3c45da4e..38d7fa6c8 100644
--- a/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs
+++ b/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs
@@ -11,7 +11,7 @@ namespace Elsa.Http.ContentWriters;
public class JsonContentFactory : IHttpContentFactory
{
///
- public IEnumerable SupportedContentTypes => new[] { MediaTypeNames.Application.Json, "text/json" };
+ public IEnumerable SupportedContentTypes => [MediaTypeNames.Application.Json, "text/json"];
///
[RequiresUnreferencedCode("The JsonSerializer type is not trim-compatible.")]
diff --git a/src/modules/Elsa.Http/ContentWriters/RawStringContent.cs b/src/modules/Elsa.Http/ContentWriters/RawStringContent.cs
index c27d476e6..6849537b6 100644
--- a/src/modules/Elsa.Http/ContentWriters/RawStringContent.cs
+++ b/src/modules/Elsa.Http/ContentWriters/RawStringContent.cs
@@ -1,48 +1,29 @@
-using System.Net;
-using System.Net.Http.Headers;
using System.Text;
namespace Elsa.Http.ContentWriters;
///
-/// A implementation that allows setting the content type without automatically appending charset information.
+/// HTTP content based on a string that preserves the provided media type as-is (no automatic charset parameter).
+/// Uses a pre-encoded byte array to guarantee Content-Length == bytes written.
///
-public class RawStringContent : HttpContent
+public sealed class RawStringContent : ByteArrayContent
{
- private readonly string _content;
- private readonly Encoding _encoding;
-
- ///
- /// Creates a new instance of the class.
- ///
- /// The content to send.
- /// The encoding to use when sending the content.
- /// The media type to use for the content.
public RawStringContent(string content, Encoding encoding, string mediaType)
+ : base(GetBytes(content, encoding))
{
- _content = content;
- _encoding = encoding;
-
- // Set the media type exactly as provided without appending charset information
- Headers.ContentType = new MediaTypeHeaderValue(mediaType);
+ // Set media type exactly as provided, without charset parameter.
+ Headers.ContentType = new(mediaType);
}
- ///
- protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) =>
- SerializeToStreamAsync(stream, context, CancellationToken.None);
-
- ///
- protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken)
+ private static byte[] GetBytes(string content, Encoding encoding)
{
- await using var writer = new StreamWriter(stream, _encoding, leaveOpen: true);
- await writer.WriteAsync(_content.AsMemory(), cancellationToken);
- await writer.FlushAsync(cancellationToken);
- }
+ ArgumentNullException.ThrowIfNull(content);
+ ArgumentNullException.ThrowIfNull(encoding);
- ///
- protected override bool TryComputeLength(out long length)
- {
- length = _encoding.GetByteCount(_content);
- return true;
+ // Ensure we don't include a BOM/preamble. Most Encoding instances can expose a preamble.
+ // If encoding has a preamble, we must not include it, so use GetBytes directly (preamble is only returned by GetPreamble()).
+ // For safety, if the encoding instance is a BOM-producing variant (e.g., new UTF8Encoding(true)),
+ // GetBytes does not include the BOM; only GetPreamble() would. So this is safe.
+ return encoding.GetBytes(content);
}
}
\ No newline at end of file