Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/WhatsApp/JsonContext.Internal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Devlooped.WhatsApp;

[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
UseStringEnumConverter = true,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower,
WriteIndented = true
)]
[JsonSerializable(typeof(GraphMethodException))]
[JsonSerializable(typeof(ErrorResponse))]
[JsonSerializable(typeof(SendResponse))]
[JsonSerializable(typeof(MessageId))]
partial class InternalJsonContext : JsonSerializerContext
{
}

record ErrorResponse(GraphMethodException Error);

record SendResponse(MessageId[] Messages);

record MessageId(string Id);
34 changes: 21 additions & 13 deletions src/WhatsApp/JsonContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@

namespace Devlooped.WhatsApp;

/// <summary>
/// Provides a source-generated JSON serialization context for the built-in types in this library,
/// optimized for web scenarios configured with custom serialization options.
/// </summary>
/// <remarks>
/// This context is used to enable high-performance JSON serialization and deserialization for the
/// specified types using source generation. It is configured with options such as snake_case property naming,
/// ignoring null values when writing, and using string-based enum serialization. The context also
/// supports case-insensitive property name matching and indented JSON output.
/// <para>
/// The <see cref="DefaultOptions"/> property provides a pre-configured instance of
/// <see cref="JsonSerializerOptions"/> that aligns with the context's settings and also includes
/// the <see cref="JavaScriptEncoder.UnsafeRelaxedJsonEscaping"/> encoder for web scenarios.
/// </para>
/// </remarks>
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
UseStringEnumConverter = true,
Expand All @@ -22,14 +37,13 @@ namespace Devlooped.WhatsApp;
[JsonSerializable(typeof(StatusMessage))]
[JsonSerializable(typeof(UnsupportedMessage))]
[JsonSerializable(typeof(MediaReference))]
[JsonSerializable(typeof(GraphMethodException))]
[JsonSerializable(typeof(ErrorResponse))]
[JsonSerializable(typeof(SendResponse))]
[JsonSerializable(typeof(MessageId))]
partial class JsonContext : JsonSerializerContext
public partial class JsonContext : JsonSerializerContext
{
static readonly Lazy<JsonSerializerOptions> options = new Lazy<JsonSerializerOptions>(() => CreateDefaultOptions());
static readonly Lazy<JsonSerializerOptions> options = new(() => CreateDefaultOptions());

/// <summary>
/// Provides a pre-configured instance of <see cref="JsonSerializerOptions"/> that aligns with the context's settings.
/// </summary>
public static JsonSerializerOptions DefaultOptions { get => options.Value; }

[UnconditionalSuppressMessage("AotAnalysis", "IL3050", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")]
Expand All @@ -53,10 +67,4 @@ static JsonSerializerOptions CreateDefaultOptions()
options.MakeReadOnly();
return options;
}
}

record ErrorResponse(GraphMethodException Error);

record SendResponse(MessageId[] Messages);

record MessageId(string Id);
}
2 changes: 1 addition & 1 deletion src/WhatsApp/WhatsAppClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public HttpClient CreateHttp(string numberId)
throw new HttpRequestException(error, null, result.StatusCode);
}

var response = await result.Content.ReadFromJsonAsync(JsonContext.Default.SendResponse);
var response = await result.Content.ReadFromJsonAsync(InternalJsonContext.Default.SendResponse);

return response?.Messages?.FirstOrDefault()?.Id;
}
Expand Down
2 changes: 1 addition & 1 deletion src/WhatsApp/WhatsAppClientExtensions.ResolveMedia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static async Task<MediaReference> ResolveMediaAsync(this IWhatsAppClient
await response.Content.LoadIntoBufferAsync();

if (!response.IsSuccessStatusCode &&
await response.Content.ReadFromJsonAsync(JsonContext.Default.ErrorResponse, cancellation) is { } error)
await response.Content.ReadFromJsonAsync(InternalJsonContext.Default.ErrorResponse, cancellation) is { } error)
throw error.Error;

response.EnsureSuccessStatusCode();
Expand Down