From fa34b4b21a226aa606cc30e9b7144f48233968fd Mon Sep 17 00:00:00 2001 From: Quetzal Rivera Date: Tue, 13 Oct 2026 21:57:54 -0600 Subject: [PATCH 1/2] fix(RichText): support string and array rich text values --- .../Converters/RichTextConverter.cs | 38 +++++++++++++++++++ .../RichMessages/RichText/RichText.cs | 2 +- .../RichMessages/RichText/RichTextArray.cs | 32 ++++++++++++++++ .../RichText/RichTextPlainText.cs | 36 ++++++++++++++++++ .../Telegram.BotAPI.Tests/Serialization.cs | 12 ++++++ 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/library/Telegram.BotAPI/RichMessages/RichText/RichTextArray.cs create mode 100644 src/library/Telegram.BotAPI/RichMessages/RichText/RichTextPlainText.cs diff --git a/src/library/Telegram.BotAPI/Converters/RichTextConverter.cs b/src/library/Telegram.BotAPI/Converters/RichTextConverter.cs index 7311f58..796b4e6 100644 --- a/src/library/Telegram.BotAPI/Converters/RichTextConverter.cs +++ b/src/library/Telegram.BotAPI/Converters/RichTextConverter.cs @@ -1,6 +1,7 @@ // Copyright (c) 2026 Quetzal Rivera. // Licensed under the MIT License, See LICENCE in the project root for license information. +using System.Text.Json; using Telegram.BotAPI.RichMessages; namespace Telegram.BotAPI.Converters; @@ -12,4 +13,41 @@ public sealed class RichTextConverter : DiscriminatorJsonConverter { /// public override string PropertyName => PropertyNames.Type; + + /// + public override RichText? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + return reader.TokenType switch + { + JsonTokenType.StartArray => new RichTextArray( + JsonSerializer.Deserialize(ref reader, options)! + ), + JsonTokenType.String => new RichTextPlainText(reader.GetString()!), + JsonTokenType.StartObject => base.Read(ref reader, typeToConvert, options), + _ => throw new JsonException( + $"Failed to deserialize RichText. Unexpected token {reader.TokenType}" + ), + }; + } + + /// + public override void Write(Utf8JsonWriter writer, RichText value, JsonSerializerOptions options) + { + if (value is RichTextArray array) + { + JsonSerializer.Serialize(writer, (IEnumerable)array, options); + } + else if (value is RichTextPlainText plainText) + { + JsonSerializer.Serialize(writer, (string)plainText, options); + } + else + { + base.Write(writer, value, options); + } + } } diff --git a/src/library/Telegram.BotAPI/RichMessages/RichText/RichText.cs b/src/library/Telegram.BotAPI/RichMessages/RichText/RichText.cs index 926f8fe..6aa0827 100644 --- a/src/library/Telegram.BotAPI/RichMessages/RichText/RichText.cs +++ b/src/library/Telegram.BotAPI/RichMessages/RichText/RichText.cs @@ -38,7 +38,7 @@ namespace Telegram.BotAPI.RichMessages; /// /// [JsonConverter(typeof(RichTextConverter))] -public abstract class RichText +public abstract partial class RichText { /// /// Type of the rich text diff --git a/src/library/Telegram.BotAPI/RichMessages/RichText/RichTextArray.cs b/src/library/Telegram.BotAPI/RichMessages/RichText/RichTextArray.cs new file mode 100644 index 0000000..4f38609 --- /dev/null +++ b/src/library/Telegram.BotAPI/RichMessages/RichText/RichTextArray.cs @@ -0,0 +1,32 @@ +using System.Collections; +using Telegram.BotAPI.Converters; + +namespace Telegram.BotAPI.RichMessages; + +/// +/// Represents an array of . +/// +[JsonConverter(typeof(RichTextConverter))] +public class RichTextArray(IEnumerable items) : RichText, IEnumerable +{ + /// + /// Type of the rich text + /// + public override string Type => "RichTextArray"; + + private readonly IEnumerable items = items; + + /// + public IEnumerator GetEnumerator() => this.items.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); +} + +public partial class RichText +{ +#pragma warning disable IDE0023 // Use block body for conversion operator +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + public static implicit operator RichText(RichText[] value) => new RichTextArray(value); +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +#pragma warning restore IDE0023 // Use block body for conversion operator +} diff --git a/src/library/Telegram.BotAPI/RichMessages/RichText/RichTextPlainText.cs b/src/library/Telegram.BotAPI/RichMessages/RichText/RichTextPlainText.cs new file mode 100644 index 0000000..9bfe0e9 --- /dev/null +++ b/src/library/Telegram.BotAPI/RichMessages/RichText/RichTextPlainText.cs @@ -0,0 +1,36 @@ +using System.Diagnostics; +using Telegram.BotAPI.Converters; + +namespace Telegram.BotAPI.RichMessages; + +/// +/// Plain text +/// +[JsonConverter(typeof(RichTextConverter))] +[DebuggerDisplay("{value}")] +public class RichTextPlainText(string plainText) : RichText +{ + /// + /// Type of the rich text + /// + public override string Type => "RichTextPlainText"; + + private readonly string value = plainText; + + /// + public override string ToString() => this.value; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable IDE0023 // Use block body for conversion operator + public static implicit operator RichTextPlainText(string value) => new(value); + + public static implicit operator string(RichTextPlainText instance) => instance.value; +} + +public partial class RichText +{ + public static implicit operator RichText(string value) => new RichTextPlainText(value); +} + +#pragma warning restore IDE0023 // Use block body for conversion operator +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member diff --git a/src/tests/Telegram.BotAPI.Tests/Serialization.cs b/src/tests/Telegram.BotAPI.Tests/Serialization.cs index b4fd0ba..866f82b 100644 --- a/src/tests/Telegram.BotAPI.Tests/Serialization.cs +++ b/src/tests/Telegram.BotAPI.Tests/Serialization.cs @@ -5,6 +5,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Telegram.BotAPI.InlineMode; +using Telegram.BotAPI.RichMessages; using Telegram.BotAPI.UpdatingMessages; namespace Telegram.BotAPI.Tests; @@ -97,4 +98,15 @@ [new InlineKeyboardButton("Button") { CallbackData = "data" }], ).MessageText ); } + + [Fact] + public void DeserializeRichText() + { + var json = + """[{"type":"bold","text":"hi"},{"type":"italic","text":["a",{"type":"bold","text":"b"}]}]"""; + var instances = JsonSerializer.Deserialize(json); + var serializedInstances = JsonSerializer.Serialize(instances); + + Assert.Equal(json, serializedInstances); + } } From 2a3a570989f93ff18035b7d6585ce80478b66de5 Mon Sep 17 00:00:00 2001 From: Quetzal Rivera Date: Tue, 13 Oct 2026 22:01:53 -0600 Subject: [PATCH 2/2] chore: update package version and release notes --- src/library/Telegram.BotAPI/Telegram.BotAPI.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/library/Telegram.BotAPI/Telegram.BotAPI.csproj b/src/library/Telegram.BotAPI/Telegram.BotAPI.csproj index 1b94d9b..b3db3e9 100644 --- a/src/library/Telegram.BotAPI/Telegram.BotAPI.csproj +++ b/src/library/Telegram.BotAPI/Telegram.BotAPI.csproj @@ -1,7 +1,7 @@  netstandard2.0 - 10.3.0 + 10.3.1 $(AssemblyName) Quetzal Rivera true @@ -25,7 +25,8 @@ https://github.com/Eptagone/Telegram.BotAPI Telegram.BotAPI - Updated to Bot API v10.3 + Fix serialization/deserialization of RichText types when the value is a + plain text or an array of RichText instances true latest-recommended README.md