From 96d5d31710fced8afb2473d0274556d0be74d32a Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 26 Feb 2026 23:26:23 +0100 Subject: [PATCH 01/12] =?UTF-8?q?=F0=9F=90=9B=20fixed=20xml=20writing=20by?= =?UTF-8?q?=20conditionally=20encapsulating=20child=20nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Converters/DefaultXmlConverter.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Cuemon.Xml/Serialization/Converters/DefaultXmlConverter.cs b/src/Cuemon.Xml/Serialization/Converters/DefaultXmlConverter.cs index bc9e3f7fa..ceb465abe 100644 --- a/src/Cuemon.Xml/Serialization/Converters/DefaultXmlConverter.cs +++ b/src/Cuemon.Xml/Serialization/Converters/DefaultXmlConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -345,9 +345,15 @@ private static bool SkipIfNullOrEmptyEnumerable(IHierarchy childNode) private void WriteXmlChildrenEncapsulated(XmlWriter writer, IHierarchy childNode, XmlQualifiedEntity qualifiedEntity) { - var encapsulate = childNode.HasChildren && Decorator.Enclose(childNode.InstanceType).IsComplex(); - if (encapsulate) { Decorator.Enclose(writer).WriteStartElement(qualifiedEntity); } + // Determine if there is a specific converter for this child node type var converter = Decorator.Enclose(Converters).FirstOrDefaultWriterConverter(childNode.InstanceType); + + // Only encapsulate (write a surrounding start/end element) when there is no dedicated converter + // for the child node. If a converter exists it is responsible for writing the proper elements + // (to avoid duplicate wrapping such as ...) + var encapsulate = childNode.HasChildren && Decorator.Enclose(childNode.InstanceType).IsComplex() && converter == null; + if (encapsulate) { Decorator.Enclose(writer).WriteStartElement(qualifiedEntity); } + if (converter != null && !qualifiedEntity.HasXmlAttributeDecoration) { converter.WriteXml(writer, childNode.Instance, qualifiedEntity); @@ -356,7 +362,8 @@ private void WriteXmlChildrenEncapsulated(XmlWriter writer, IHierarchy c { WriteXmlNodes(writer, childNode); } + if (encapsulate) { writer.WriteEndElement(); } } } -} \ No newline at end of file +} From c013dbccd852e986cbca064e34b6b8cf28f0337b Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 00:15:36 +0100 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9C=A8=20add=20minimal=20xml=20options?= =?UTF-8?q?=20extension=20method=20for=20service=20collection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ServiceCollectionExtensions.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/Cuemon.Extensions.AspNetCore.Xml/ServiceCollectionExtensions.cs diff --git a/src/Cuemon.Extensions.AspNetCore.Xml/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Xml/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..3d468ccfa --- /dev/null +++ b/src/Cuemon.Extensions.AspNetCore.Xml/ServiceCollectionExtensions.cs @@ -0,0 +1,28 @@ +using System; +using Cuemon.Extensions.AspNetCore.Xml.Formatters; +using Cuemon.Xml.Serialization.Formatters; +using Microsoft.Extensions.DependencyInjection; + +namespace Cuemon.Extensions.AspNetCore.Xml +{ + /// + /// Extension methods for the interface. + /// + public static class ServiceCollectionExtensions + { + /// + /// Adds a service to the specified . + /// + /// The to add services to. + /// The which may be configured. + /// An that can be used to further configure other services. + /// + /// cannot be null. + /// + public static IServiceCollection AddMinimalXmlOptions(this IServiceCollection services, Action setup = null) + { + Validator.ThrowIfNull(services); + return services.AddXmlExceptionResponseFormatter(setup); + } + } +} From 3de9f862bb96558843e7ac759653927e7610bfe1 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 00:17:11 +0100 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9C=A8=20add=20flattenItems=20option?= =?UTF-8?q?=20for=20enumerable=20XML=20serialization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Converters/XmlConverterExtensions.cs | 7 +- .../XmlConverterDecoratorExtensions.cs | 88 +++++++++++++++---- .../Formatters/XmlFormatterOptions.cs | 9 +- .../Serialization/XmlSerializerOptions.cs | 10 ++- 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/Cuemon.Extensions.Xml/Serialization/Converters/XmlConverterExtensions.cs b/src/Cuemon.Extensions.Xml/Serialization/Converters/XmlConverterExtensions.cs index df8cc1920..f91813b4d 100644 --- a/src/Cuemon.Extensions.Xml/Serialization/Converters/XmlConverterExtensions.cs +++ b/src/Cuemon.Extensions.Xml/Serialization/Converters/XmlConverterExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Xml; @@ -86,14 +86,15 @@ public static IList InsertXmlConverter(this IList /// Adds an XML converter to the list. /// /// The to extend. + /// When true and a qualified element name is available, each collection item is serialized as a repeated element using that name instead of being wrapped in a generic Item element. The default is false. /// A reference to after the operation has completed. /// /// cannot be null. /// - public static IList AddEnumerableConverter(this IList converters) + public static IList AddEnumerableConverter(this IList converters, bool flattenItems = false) { Validator.ThrowIfNull(converters); - return Decorator.Enclose(converters).AddEnumerableConverter().Inner; + return Decorator.Enclose(converters).AddEnumerableConverter(flattenItems).Inner; } /// diff --git a/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs b/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs index 4310b99b1..3eedc3c67 100644 --- a/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs +++ b/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Globalization; @@ -92,24 +92,28 @@ public static IDecorator> InsertXmlConverter(this IDecora /// Adds an XML converter to the enclosed of the specified . /// /// The to extend. + /// When true and a qualified element name is available, each collection item is serialized as a repeated element using that name instead of being wrapped in a generic Item element. The default is false. /// A reference to after the operation has completed. /// /// cannot be null. /// - public static IDecorator> AddEnumerableConverter(this IDecorator> decorator) + public static IDecorator> AddEnumerableConverter(this IDecorator> decorator, bool flattenItems = false) { Validator.ThrowIfNull(decorator); decorator.AddXmlConverter((w, o, q) => { if (w.WriteState == WriteState.Start && q == null && !(o is IDictionary || o is IList)) { q = new XmlQualifiedEntity("Enumerable"); } - Decorator.Enclose(w).WriteXmlRootElement(o, (writer, sequence, _) => - { - var type = sequence.GetType(); - var hasKeyValuePairType = type.GetGenericArguments().Any(gt => Decorator.Enclose(gt).HasKeyValuePairImplementation()); - if (Decorator.Enclose(type).HasDictionaryImplementation() || hasKeyValuePairType) + var seqType = o.GetType(); + var hasKeyValuePairType = seqType.GetGenericArguments().Any(gt => Decorator.Enclose(gt).HasKeyValuePairImplementation()); + var isDictionaryLike = Decorator.Enclose(seqType).HasDictionaryImplementation() || hasKeyValuePairType; + + if (flattenItems && q != null) + { + if (isDictionaryLike) { - foreach (var element in sequence) + w.WriteStartElement(q.LocalName); + foreach (var element in o) { var elementType = element.GetType(); var keyProperty = elementType.GetProperty("Key"); @@ -118,38 +122,84 @@ public static IDecorator> AddEnumerableConverter(this IDecor var valueValue = valueProperty.GetValue(element, null); var valuePropertyType = valueProperty.PropertyType; if (valuePropertyType == typeof(object) && valueValue != null) { valuePropertyType = valueValue.GetType(); } - writer.WriteStartElement("Item"); - writer.WriteAttributeString("name", keyValue.ToString()); + var keyName = Decorator.Enclose(keyValue.ToString()).SanitizeXmlElementName(); if (Decorator.Enclose(valuePropertyType).IsComplex()) { - Decorator.Enclose(writer).WriteObject(valueValue, valuePropertyType); + Decorator.Enclose(w).WriteObject(valueValue, valuePropertyType, opts => opts.Settings.RootName = new XmlQualifiedEntity(keyName)); } else { - writer.WriteValue(valueValue); + w.WriteElementString(keyName, Convert.ToString(valueValue, CultureInfo.InvariantCulture)); } - writer.WriteEndElement(); } + w.WriteEndElement(); } else { - foreach (var item in sequence) + foreach (var item in o) { if (item == null) { continue; } var itemType = item.GetType(); - writer.WriteStartElement("Item"); if (Decorator.Enclose(itemType).IsComplex()) { - Decorator.Enclose(writer).WriteObject(item, itemType); + var localName = q.LocalName; + Decorator.Enclose(w).WriteObject(item, itemType, opts => opts.Settings.RootName = new XmlQualifiedEntity(localName)); } else { - writer.WriteValue(item); + w.WriteElementString(q.LocalName, Convert.ToString(item, CultureInfo.InvariantCulture)); } - writer.WriteEndElement(); } } - }, q); + } + else + { + Decorator.Enclose(w).WriteXmlRootElement(o, (writer, sequence, _) => + { + if (isDictionaryLike) + { + foreach (var element in sequence) + { + var elementType = element.GetType(); + var keyProperty = elementType.GetProperty("Key"); + var valueProperty = elementType.GetProperty("Value"); + var keyValue = keyProperty.GetValue(element, null); + var valueValue = valueProperty.GetValue(element, null); + var valuePropertyType = valueProperty.PropertyType; + if (valuePropertyType == typeof(object) && valueValue != null) { valuePropertyType = valueValue.GetType(); } + writer.WriteStartElement("Item"); + writer.WriteAttributeString("name", keyValue.ToString()); + if (Decorator.Enclose(valuePropertyType).IsComplex()) + { + Decorator.Enclose(writer).WriteObject(valueValue, valuePropertyType); + } + else + { + writer.WriteValue(valueValue); + } + writer.WriteEndElement(); + } + } + else + { + foreach (var item in sequence) + { + if (item == null) { continue; } + var itemType = item.GetType(); + writer.WriteStartElement("Item"); + if (Decorator.Enclose(itemType).IsComplex()) + { + Decorator.Enclose(writer).WriteObject(item, itemType); + } + else + { + writer.WriteValue(item); + } + writer.WriteEndElement(); + } + } + }, q); + } }, (reader, type) => Decorator.Enclose(type).HasDictionaryImplementation() ? Decorator.Enclose(Decorator.Enclose(reader).ToHierarchy()).UseDictionary(type.GetGenericArguments()) : Decorator.Enclose(Decorator.Enclose(reader).ToHierarchy()).UseCollection(type.GetGenericArguments().First()), type => type != typeof(string)); return decorator; } diff --git a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs index de831719d..0c53ec69e 100644 --- a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs +++ b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Collections; using System.Collections.Generic; using System.Net.Http.Headers; using Cuemon.Configuration; @@ -126,6 +127,12 @@ internal XmlSerializerOptions RefreshWithConverterDependencies() if (!_refreshed) { _refreshed = true; + if (Settings.FlattenCollectionItems) + { + var existing = Decorator.Enclose(Settings.Converters).FirstOrDefaultWriterConverter(typeof(IEnumerable)); + if (existing != null) { Settings.Converters.Remove(existing); } + Decorator.Enclose(Settings.Converters).AddEnumerableConverter(flattenItems: true); + } Decorator.Enclose(Settings.Converters) .AddExceptionConverter(SensitivityDetails.HasFlag(FaultSensitivityDetails.StackTrace), SensitivityDetails.HasFlag(FaultSensitivityDetails.Data)) .AddExceptionDescriptorConverter(o => o.SensitivityDetails = SensitivityDetails); diff --git a/src/Cuemon.Xml/Serialization/XmlSerializerOptions.cs b/src/Cuemon.Xml/Serialization/XmlSerializerOptions.cs index 323b2dc68..6de6d21fe 100644 --- a/src/Cuemon.Xml/Serialization/XmlSerializerOptions.cs +++ b/src/Cuemon.Xml/Serialization/XmlSerializerOptions.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Xml; using Cuemon.Xml.Serialization.Converters; @@ -67,5 +67,11 @@ public XmlSerializerOptions() /// /// The name of the XML root element. public XmlQualifiedEntity RootName { get; set; } + + /// + /// Gets or sets a value indicating whether collection items should be serialized as repeated elements using the property name instead of being wrapped in a generic Item element. + /// + /// true to emit one repeated element per item named after the enclosing property; false to use the default Item wrapper. The default is false. + public bool FlattenCollectionItems { get; set; } } -} \ No newline at end of file +} From bc5e7bc4c0afa8ae9e3507a0f71ee01e82fa9565 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 00:17:31 +0100 Subject: [PATCH 04/12] =?UTF-8?q?=E2=9C=85=20add=20xml=20serialization=20t?= =?UTF-8?q?ests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Xml/ServiceCollectionExtensionsTest.cs | 72 ++++++++ test/Cuemon.Xml.Tests/Assets/RegionStats.cs | 11 ++ test/Cuemon.Xml.Tests/Assets/WorldNode.cs | 29 ++++ .../Formatters/XmlFormatterTest.cs | 160 +++++++++++++++++- 4 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 test/Cuemon.Extensions.AspNetCore.Tests/Xml/ServiceCollectionExtensionsTest.cs create mode 100644 test/Cuemon.Xml.Tests/Assets/RegionStats.cs create mode 100644 test/Cuemon.Xml.Tests/Assets/WorldNode.cs diff --git a/test/Cuemon.Extensions.AspNetCore.Tests/Xml/ServiceCollectionExtensionsTest.cs b/test/Cuemon.Extensions.AspNetCore.Tests/Xml/ServiceCollectionExtensionsTest.cs new file mode 100644 index 000000000..e5353cab5 --- /dev/null +++ b/test/Cuemon.Extensions.AspNetCore.Tests/Xml/ServiceCollectionExtensionsTest.cs @@ -0,0 +1,72 @@ +using System; +using System.Linq; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.Extensions.AspNetCore.Diagnostics; +using Cuemon.Xml.Serialization.Formatters; +using Codebelt.Extensions.Xunit; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Cuemon.Extensions.AspNetCore.Xml +{ + public class ServiceCollectionExtensionsTest : Test + { + public ServiceCollectionExtensionsTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void AddMinimalXmlOptions_ShouldThrowArgumentNullException_WhenServicesIsNull() + { + Assert.Throws("services", () => ServiceCollectionExtensions.AddMinimalXmlOptions(null)); + } + + [Fact] + public void AddMinimalXmlOptions_ShouldRegisterXmlFormatterOptions() + { + var sut = new ServiceCollection(); + + sut.AddMinimalXmlOptions(); + + var count = sut.Count(sd => + sd.ServiceType == typeof(IConfigureOptions)); + + TestOutput.WriteLine($"IConfigureOptions registrations: {count}"); + + Assert.True(count >= 1); + } + + [Fact] + public void AddMinimalXmlOptions_ShouldAlsoRegisterXmlExceptionResponseFormatter() + { + var sut = new ServiceCollection(); + sut.AddFaultDescriptorOptions(); + + sut.AddMinimalXmlOptions(); + + var hasFormatter = sut.Any(sd => + sd.ServiceType == typeof(HttpExceptionDescriptorResponseFormatter)); + + Assert.True(hasFormatter); + } + + [Fact] + public void AddMinimalXmlOptions_ShouldOnlyRegisterXmlExceptionResponseFormatterOnce_WhenCalledMultipleTimes() + { + var sut = new ServiceCollection(); + sut.AddFaultDescriptorOptions(); + + sut.AddMinimalXmlOptions(); + sut.AddMinimalXmlOptions(); + sut.AddMinimalXmlOptions(); + + var count = sut.Count(sd => + sd.ServiceType == typeof(HttpExceptionDescriptorResponseFormatter)); + + TestOutput.WriteLine($"HttpExceptionDescriptorResponseFormatter registrations: {count}"); + + Assert.Equal(1, count); + } + } +} diff --git a/test/Cuemon.Xml.Tests/Assets/RegionStats.cs b/test/Cuemon.Xml.Tests/Assets/RegionStats.cs new file mode 100644 index 000000000..68e26d728 --- /dev/null +++ b/test/Cuemon.Xml.Tests/Assets/RegionStats.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Cuemon.Xml.Assets +{ + public class RegionStats + { + public string Name { get; set; } + + public Dictionary Indicators { get; set; } + } +} diff --git a/test/Cuemon.Xml.Tests/Assets/WorldNode.cs b/test/Cuemon.Xml.Tests/Assets/WorldNode.cs new file mode 100644 index 000000000..9d6d9146d --- /dev/null +++ b/test/Cuemon.Xml.Tests/Assets/WorldNode.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Cuemon.Xml.Assets +{ + public class WorldNode + { + public string Code { get; set; } + + public string Name { get; set; } + + public string Kind { get; set; } + + public WorldLinks Links { get; set; } + } + + public class WorldLinks + { + public Link Self { get; set; } + + public List Children { get; set; } + } + + public class Link + { + public string Href { get; set; } + + public string Title { get; set; } + } +} diff --git a/test/Cuemon.Xml.Tests/Serialization/Formatters/XmlFormatterTest.cs b/test/Cuemon.Xml.Tests/Serialization/Formatters/XmlFormatterTest.cs index 2247656fb..33c4e8d82 100644 --- a/test/Cuemon.Xml.Tests/Serialization/Formatters/XmlFormatterTest.cs +++ b/test/Cuemon.Xml.Tests/Serialization/Formatters/XmlFormatterTest.cs @@ -1,11 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; using System.Xml; using Cuemon.Diagnostics; -using Cuemon.Extensions; using Cuemon.Extensions.IO; using Codebelt.Extensions.Xunit; using Cuemon.IO; @@ -106,6 +105,161 @@ public void Serialize_ShouldSerializeUsingStringConverterWrappedInCData() result.Dispose(); } + [Fact] + public void Serialize_ShouldSerializeWorldNodeHierarchy() + { + var world = new WorldNode + { + Code = "001", + Name = "World", + Kind = "World", + Links = new WorldLinks + { + Self = new Link { Href = "/", Title = "World" }, + Children = new List + { + new Link { Href = "/regions/002", Title = "Africa" }, + new Link { Href = "/regions/009", Title = "Oceania" }, + new Link { Href = "/regions/010", Title = "Antarctica" }, + new Link { Href = "/regions/019", Title = "Americas" }, + new Link { Href = "/regions/142", Title = "Asia" }, + new Link { Href = "/regions/150", Title = "Europe" } + } + } + }; + + var sut = new XmlFormatter(o => o.Settings.Writer.Indent = true); + var result = sut.Serialize(world); + var x = new XmlDocument(); + x.Load(result); + + TestOutput.WriteLine(Decorator.Enclose(result).ToEncodedString()); + + Assert.Contains("001", x.OuterXml); + Assert.Contains("World", x.OuterXml); + Assert.Contains("World", x.OuterXml); + Assert.Contains("/", x.OuterXml); + Assert.Contains("World", x.OuterXml); + Assert.Contains("/regions/002", x.OuterXml); + Assert.Contains("Africa", x.OuterXml); + Assert.Contains("/regions/150", x.OuterXml); + + result.Dispose(); + } + + [Fact] + public void Serialize_ShouldProduce_PascalCase_Structure_ForWorldNode() + { + var world = new WorldNode + { + Code = "001", + Name = "World", + Kind = "World", + Links = new WorldLinks + { + Self = new Link { Href = "/", Title = "World" }, + Children = new List + { + new Link { Href = "/regions/002", Title = "Africa" }, + new Link { Href = "/regions/009", Title = "Oceania" }, + new Link { Href = "/regions/010", Title = "Antarctica" }, + new Link { Href = "/regions/019", Title = "Americas" }, + new Link { Href = "/regions/142", Title = "Asia" }, + new Link { Href = "/regions/150", Title = "Europe" } + } + } + }; + + var sut = new XmlFormatter(o => + { + o.Settings.Writer.Indent = true; + o.Settings.FlattenCollectionItems = true; + }); + var result = sut.Serialize(world); + var x = new XmlDocument(); + x.Load(result); + + TestOutput.WriteLine(Decorator.Enclose(result).ToEncodedString()); + + Assert.Equal("WorldNode", x.DocumentElement.Name); + Assert.Contains("001", x.OuterXml); + Assert.Contains("World", x.OuterXml); + Assert.Contains("World", x.OuterXml); + Assert.Contains("", x.OuterXml); + Assert.Contains("", x.OuterXml); + Assert.Contains("/", x.OuterXml); + Assert.Contains("World", x.OuterXml); + Assert.DoesNotContain("", x.OuterXml); + Assert.Contains("/regions/002", x.OuterXml); + Assert.Contains("Africa", x.OuterXml); + Assert.Contains("/regions/150", x.OuterXml); + + result.Dispose(); + } + + [Fact] + public void Serialize_ShouldSerializeUsingEnumerableConverter_DictionaryProperty() + { + var sut1 = new RegionStats + { + Name = "Africa", + Indicators = new Dictionary + { + { "Population", 1400000000 }, + { "Countries", 54 } + } + }; + + var sut = new XmlFormatter(o => o.Settings.Writer.Indent = true); + var result = sut.Serialize(sut1); + var x = new XmlDocument(); + x.Load(result); + + TestOutput.WriteLine(Decorator.Enclose(result).ToEncodedString()); + + Assert.Equal("RegionStats", x.DocumentElement.Name); + Assert.Contains("Africa", x.OuterXml); + Assert.Contains("", x.OuterXml); + Assert.Contains("1400000000", x.OuterXml); + Assert.Contains("54", x.OuterXml); + + result.Dispose(); + } + + [Fact] + public void Serialize_ShouldSerializeUsingFlattenedConverter_DictionaryProperty() + { + var sut1 = new RegionStats + { + Name = "Africa", + Indicators = new Dictionary + { + { "Population", 1400000000 }, + { "Countries", 54 } + } + }; + + var sut = new XmlFormatter(o => + { + o.Settings.Writer.Indent = true; + o.Settings.FlattenCollectionItems = true; + }); + var result = sut.Serialize(sut1); + var x = new XmlDocument(); + x.Load(result); + + TestOutput.WriteLine(Decorator.Enclose(result).ToEncodedString()); + + Assert.Equal("RegionStats", x.DocumentElement.Name); + Assert.Contains("Africa", x.OuterXml); + Assert.DoesNotContain("", x.OuterXml); + Assert.Contains("1400000000", x.OuterXml); + Assert.Contains("54", x.OuterXml); + + result.Dispose(); + } + [Fact] public void Serialize_ShouldSerializeUsingStringConverter() { @@ -447,4 +601,4 @@ public void Serialize_ShouldSerializeUsingExceptionDescriptorConverter_ExcludeEv result.Dispose(); } } -} \ No newline at end of file +} From 09ad4a9f2fedb780c8a49a1d6c266df0045b39a7 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 00:29:47 +0100 Subject: [PATCH 05/12] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20bump=20dependencies?= =?UTF-8?q?=20for=20benchmarkdotnet=20and=20xunit=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .docfx/Dockerfile.docfx | 2 +- Directory.Packages.props | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index d66eaab59..aa3281c83 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -3,7 +3,7 @@ FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base RUN rm -rf /usr/share/nginx/html/* -FROM --platform=$BUILDPLATFORM codebeltnet/docfx:2.78.4 AS build +FROM --platform=$BUILDPLATFORM codebeltnet/docfx:2.78.5 AS build ADD [".", "docfx"] diff --git a/Directory.Packages.props b/Directory.Packages.props index 46bc19c97..b255f63f3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,12 +6,12 @@ - - - - + + + + - + From 5d863a3661a102e1aad08773d32aa86a89f50a71 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 00:30:04 +0100 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20remove=20service?= =?UTF-8?q?=20update=20workflow=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/service-update.yml | 139 --------------------------- 1 file changed, 139 deletions(-) delete mode 100644 .github/workflows/service-update.yml diff --git a/.github/workflows/service-update.yml b/.github/workflows/service-update.yml deleted file mode 100644 index d08f940ee..000000000 --- a/.github/workflows/service-update.yml +++ /dev/null @@ -1,139 +0,0 @@ -name: Service Update - -on: - repository_dispatch: - types: [codebelt-service-update] - workflow_dispatch: - inputs: - source_repo: - description: 'Triggering source repo name (e.g. cuemon)' - required: false - default: '' - source_version: - description: 'Version released by source (e.g. 10.3.0)' - required: false - default: '' - dry_run: - type: boolean - description: 'Dry run — show changes but do not commit or open PR' - default: false - -permissions: - contents: write - pull-requests: write - -jobs: - service-update: - runs-on: ubuntu-24.04 - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Resolve trigger inputs - id: trigger - run: | - SOURCE="${{ github.event.client_payload.source_repo || github.event.inputs.source_repo }}" - VERSION="${{ github.event.client_payload.source_version || github.event.inputs.source_version }}" - echo "source=$SOURCE" >> $GITHUB_OUTPUT - echo "version=$VERSION" >> $GITHUB_OUTPUT - - - name: Determine new version for this repo - id: newver - run: | - CURRENT=$(grep -oP '(?<=## \[)[\d.]+(?=\])' CHANGELOG.md | head -1) - NEW=$(echo "$CURRENT" | awk -F. '{printf "%s.%s.%d", $1, $2, $3+1}') - BRANCH="v${NEW}/service-update" - echo "current=$CURRENT" >> $GITHUB_OUTPUT - echo "new=$NEW" >> $GITHUB_OUTPUT - echo "branch=$BRANCH" >> $GITHUB_OUTPUT - - - name: Generate codebelt-aicia token - id: app-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ vars.CODEBELT_AICIA_APP_ID }} - private-key: ${{ secrets.CODEBELT_AICIA_PRIVATE_KEY }} - owner: codebeltnet - - - name: Bump NuGet packages - run: python3 .github/scripts/bump-nuget.py - env: - TRIGGER_SOURCE: ${{ steps.trigger.outputs.source }} - TRIGGER_VERSION: ${{ steps.trigger.outputs.version }} - - - name: Update PackageReleaseNotes.txt - run: | - NEW="${{ steps.newver.outputs.new }}" - for f in .nuget/*/PackageReleaseNotes.txt; do - [ -f "$f" ] || continue - TFM=$(grep -m1 "^Availability:" "$f" | sed 's/Availability: //' || echo ".NET 10, .NET 9 and .NET Standard 2.0") - ENTRY="Version ${NEW}\nAvailability: ${TFM}\n \n# ALM\n- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)\n \n" - { printf "$ENTRY"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f" - done - - - name: Update CHANGELOG.md - run: | - python3 - <<'EOF' - import os, re - from datetime import date - new_ver = os.environ['NEW_VERSION'] - today = date.today().isoformat() - entry = f"## [{new_ver}] - {today}\n\nThis is a service update that focuses on package dependencies.\n\n" - with open("CHANGELOG.md") as f: - content = f.read() - idx = content.find("## [") - content = (content[:idx] + entry + content[idx:]) if idx != -1 else (content + entry) - with open("CHANGELOG.md", "w") as f: - f.write(content) - print(f"CHANGELOG updated for v{new_ver}") - EOF - env: - NEW_VERSION: ${{ steps.newver.outputs.new }} - - # Note: Docker image bumps removed in favor of manual updates - # The automated selection was picking wrong variants (e.g., mono-* instead of standard) - # TODO: Move to hosted service for smarter image selection - - - name: Show diff (dry run) - if: ${{ github.event.inputs.dry_run == 'true' }} - run: git diff - - - name: Create branch and open PR - if: ${{ github.event.inputs.dry_run != 'true' }} - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - NEW="${{ steps.newver.outputs.new }}" - BRANCH="${{ steps.newver.outputs.branch }}" - SOURCE="${{ steps.trigger.outputs.source }}" - SRC_VER="${{ steps.trigger.outputs.version }}" - - git config user.name "codebelt-aicia[bot]" - git config user.email "codebelt-aicia[bot]@users.noreply.github.com" - git checkout -b "$BRANCH" - git add -A - git diff --cached --quiet && echo "Nothing changed - skipping PR." && exit 0 - git commit -m "V${NEW}/service update" - git push origin "$BRANCH" - - echo "This is a service update that focuses on package dependencies." > pr_body.txt - echo "" >> pr_body.txt - echo "Automated changes:" >> pr_body.txt - echo "- Codebelt/Cuemon package versions bumped to latest compatible" >> pr_body.txt - echo "- PackageReleaseNotes.txt updated for v${NEW}" >> pr_body.txt - echo "- CHANGELOG.md entry added for v${NEW}" >> pr_body.txt - echo "" >> pr_body.txt - echo "Note: Third-party packages (Microsoft.Extensions.*, BenchmarkDotNet, etc.) are not auto-updated." >> pr_body.txt - echo "Use Dependabot or manual updates for those." >> pr_body.txt - echo "" >> pr_body.txt - echo "Generated by codebelt-aicia" >> pr_body.txt - if [ -n "$SOURCE" ] && [ -n "$SRC_VER" ]; then - echo "Triggered by: ${SOURCE} @ ${SRC_VER}" >> pr_body.txt - else - echo "Triggered by: manual workflow dispatch" >> pr_body.txt - fi - - gh pr create --title "V${NEW}/service update" --body-file pr_body.txt --base main --head "$BRANCH" --assignee gimlichael From 9cb701824ffbc02c7ed3f50f52c1b219c0a45657 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 00:47:53 +0100 Subject: [PATCH 07/12] =?UTF-8?q?=F0=9F=93=A6=EF=B8=8F=20updated=20NuGet?= =?UTF-8?q?=20package=20definition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Core.App/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Core/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Data/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.IO/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Net/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Resilience/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Threading/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Xml/PackageReleaseNotes.txt | 6 ++++++ 42 files changed, 252 insertions(+) diff --git a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt index 874794bf3..87da3de80 100644 --- a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt index 91c889791..b9a324bec 100644 --- a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt index f54188d20..6f1224c8c 100644 --- a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt index 874794bf3..87da3de80 100644 --- a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt index 60091d293..878296d74 100644 --- a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt index 3276b51af..c4439657c 100644 --- a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Core/PackageReleaseNotes.txt index a68bdb82e..4229ee2d9 100644 --- a/.nuget/Cuemon.Core/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Core/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt index e27c713aa..aad86751c 100644 --- a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Data/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Data/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Data/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt index 874794bf3..87da3de80 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt index b46a2fcd5..4a4275970 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt index da86eaaca..66bcc196b 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt index 874794bf3..87da3de80 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt index c36b38ae7..17606033c 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt index 706f6792b..fa5435d17 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt index 6d638343e..3a05716df 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt index d329d4373..382a9d087 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10 and .NET 9 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt index c5893b347..71c9aaf74 100644 --- a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt index b42913b9c..24191d252 100644 --- a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt index aa6ad239b..0a6f4ce6c 100644 --- a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt index a8f7a4611..ed9e5d9b5 100644 --- a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt index 066fb2a6e..08515d30d 100644 --- a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt index d53d564ce..1159b055a 100644 --- a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt index c9dbd0338..41d751cde 100644 --- a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt index d705a5457..42877a15a 100644 --- a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt index 670f601d6..76f989d63 100644 --- a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.IO/PackageReleaseNotes.txt index 42afd0a51..1420c5397 100644 --- a/.nuget/Cuemon.IO/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.IO/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Net/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Net/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Net/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt index cac38ed7a..1464c21f1 100644 --- a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt index 6616678d0..5a119274c 100644 --- a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt index 1c78ae751..f2f21801f 100644 --- a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt index e60a226ac..449bd5ca3 100644 --- a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.4.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   From 53c6a547b6a1df1cbbbc69574a26fb040d91cb59 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 01:02:48 +0100 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=A4=96=20add=20prompt=20for=20popul?= =?UTF-8?q?ating=20PackageReleaseNotes.txt=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/prompts/nuget-pouplate.prompt.md | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/prompts/nuget-pouplate.prompt.md diff --git a/.github/prompts/nuget-pouplate.prompt.md b/.github/prompts/nuget-pouplate.prompt.md new file mode 100644 index 000000000..5c0e2dffa --- /dev/null +++ b/.github/prompts/nuget-pouplate.prompt.md @@ -0,0 +1,50 @@ +--- +mode: agent +description: 'Prompt for populating commits to PackageReleaseNotes.txt files under .nuget/**' +--- + +Purpose: deterministic, low-analysis instructions so automated runs populate release-note change bullets for the current unreleased version block. + +Behavior (exact): +- For every file matching `.nuget/**/PackageReleaseNotes.txt`: + 1. Read line 1 and extract `current-version` from `Version: x.y.z` (strict semantic version format). + 2. Find the next line below line 1 that matches `Version:` and extract `previous-version` from `Version: x.y.z`. + 3. If either version cannot be extracted, do nothing for that file. + 4. Define the editable range as the lines after the first `Availability:` line in the current block and before the next `Version:` match (`previous-version`). + 5. Resolve release anchor tag by matching `previous-version` to git tag `v` first, then ``. + 6. If neither tag exists, do nothing for that file. + 7. Collect commits for that package from `tag(previous-version)..HEAD` using path scope derived from the package name: + - Package name = folder name under `.nuget/` for the file. + - Primary source path scope: `src//**`. + 8. Convert commits to release-note bullets using the existing release-note style and headings in that file. + 9. Replace only the change-content area inside the current block range: + - Keep `Version:` and `Availability:` unchanged. + - Keep `# ALM` section untouched if already present. + - Populate or update `# New Features`, `# Improvements`, and `# Bug Fixes` as needed. + - Do not modify any content outside the current block range. + 10. Save the file in-place and continue to the next file. + +Transformation rules (strict): +- Use heading names exactly: `# New Features`, `# Improvements`, `# Bug Fixes`. +- Use bullet style exactly: `- ` where `` is uppercase and one of `ADDED`, `EXTENDED`, `CHANGED`, `OPTIMIZED`, `FIXED`, `REMOVED`. +- Keep one bullet per logical change; deduplicate repeated commit messages. +- Prefer imperative, product-facing summaries over raw commit text. +- Mention concrete type/member names and namespace when identifiable, matching existing tone. +- Preserve NBSP-only spacer lines (`U+00A0`) between sections. +- Alaways end with a newline followed by spacer lines (`U+00A0`) between sections. +- Do not reorder historical sections and do not rewrite previous version blocks. + +Tag and range rules: +- The comparison baseline is always `previous-version` (the next `Version:` in the same file), not `current-version`. +- Commit range is `tag(previous-version)..HEAD`. +- Ignore merge commits unless they contain meaningful release-note content not present in child commits. +- If range contains no relevant commits for the scoped paths, leave the current block unchanged. + +Notes: +- Do not infer target versions from changelog text; parse only explicit `Version: x.y.z` lines. +- Keep edits minimal and strictly inside the current version block. +- DO NOT REMOVE THE ASCII 0xA0 NBSP CHARACTERS OR RUN ANY SORT OF TRIM on spacer lines. +- Do not open PRs or create branches. + +Example run command (agent): +`run: /nuget-populate` From 587651e7aebe9539730fcfd500ae34d9d7746e4c Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 01:24:24 +0100 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=93=A6=EF=B8=8F=20updated=20NuGet?= =?UTF-8?q?=20package=20definition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nuget/Cuemon.Core/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 3 +++ .nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt | 3 +++ .nuget/Cuemon.Xml/PackageReleaseNotes.txt | 7 +++++++ 4 files changed, 19 insertions(+) diff --git a/.nuget/Cuemon.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Core/PackageReleaseNotes.txt index 4229ee2d9..7061f355b 100644 --- a/.nuget/Cuemon.Core/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Core/PackageReleaseNotes.txt @@ -4,6 +4,12 @@ Availability: .NET 10, .NET 9 and .NET Standard 2.0 # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)   +# Improvements +- CHANGED World class in the Cuemon.Globalization namespace to exclude redundancies in region handling +  +# Bug Fixes +- FIXED World class in the Cuemon.Globalization namespace where retrieving countries by code in GetStatisticalRegion was not included +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt index 3a05716df..aeb9df430 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt @@ -4,6 +4,9 @@ Availability: .NET 10 and .NET 9 # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)   +# New Features +- ADDED ServiceCollectionExtensions class in the Cuemon.Extensions.AspNetCore.Xml namespace with AddMinimalXmlOptions extension method for registering XmlFormatterOptions with IServiceCollection +  Version: 10.3.0 Availability: .NET 10 and .NET 9   diff --git a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt index 76f989d63..4091d0f3d 100644 --- a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt @@ -4,6 +4,9 @@ Availability: .NET 10, .NET 9 and .NET Standard 2.0 # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)   +# Improvements +- CHANGED XmlConverterExtensions in the Cuemon.Extensions.Xml.Serialization.Converters namespace to support flattening items when serializing in the AddEnumerableConverter method +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   diff --git a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt index 449bd5ca3..0b0cac96a 100644 --- a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt @@ -4,6 +4,13 @@ Availability: .NET 10, .NET 9 and .NET Standard 2.0 # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)   +# New Features +- ADDED FlattenCollectionItems property to XmlSerializerOptions in the Cuemon.Xml.Serialization namespace to control item flattening during enumerable XML serialization +- ADDED flattenItems parameter to AddEnumerableConverter in XmlConverterDecoratorExtensions in the Cuemon.Xml.Serialization.Converters namespace to support item flattening +  +# Bug Fixes +- FIXED DefaultXmlConverter class in the Cuemon.Xml.Serialization.Converters namespace to conditionally encapsulate child nodes and prevent duplicate element wrapping +  Version: 10.3.0 Availability: .NET 10, .NET 9 and .NET Standard 2.0   From 124ee9093a3ab0d8c99c028bc606e4a317d7c33c Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 27 Feb 2026 01:26:22 +0100 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=92=AC=20updated=20community=20heal?= =?UTF-8?q?th=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c634fc87b..994df6b93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. +## [10.4.0] - 2026-02-27 + +This is a minor release that introduces support for flattening items in enumerable XML serialization, while also improving the behavior of the default XML converter to prevent duplicate element wrapping. A few bug fixes and improvements were also included in this release. + +### Added + +- `ServiceCollectionExtensions` class in the Cuemon.Extensions.AspNetCore.Xml namespace with `AddMinimalXmlOptions` extension method. + +### Fixed + +- `DefaultXmlConverter` class in the `Cuemon.Xml.Serialization.Converters` namespace to prevent duplicate element wrapping, +- `World` class in the Cuemon.Globalization namespace to include countries not previously included in the `GetStatisticalRegion` method. + +### Changed + +- `World` class in the Cuemon.Globalization namespace to exclude redundancies in `RegionInfo` handling, +- `XmlConverterExtensions` class in the Cuemon.Extensions.Xml.Serialization.Converters namespace to support flattening items when serializing in the `AddEnumerableConverter` method, +- `XmlSerializerOptions` class in the `Cuemon.Xml.Serialization` namespace was extended with `FlattenCollectionItems` property to control item flattening during enumerable XML serialization, +- + ## [10.3.0] - 2026-02-19 This is a minor release that introduces assembly discovery utilities and improved minimal API formatter integration, while also tightening option registration behavior across ASP.NET Core formatter setup. From 3a125d622604bb331d98c01cfd1402bdbfb9f561 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 01:42:03 +0000 Subject: [PATCH 11/12] Initial plan From 22f0d1cf32616211254d0c2515886f4ca5121636 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 01:52:47 +0000 Subject: [PATCH 12/12] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20address=20review=20f?= =?UTF-8?q?eedback=20on=20XML=20flatten=20serialization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: gimlichael <8550919+gimlichael@users.noreply.github.com> --- .../XmlConverterDecoratorExtensions.cs | 19 +++++++++++++------ .../Formatters/XmlFormatterOptions.cs | 11 ++++++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs b/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs index 3eedc3c67..f1fd4f50c 100644 --- a/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs +++ b/src/Cuemon.Xml/Extensions/Serialization/Converters/XmlConverterDecoratorExtensions.cs @@ -112,7 +112,7 @@ public static IDecorator> AddEnumerableConverter(this IDecor { if (isDictionaryLike) { - w.WriteStartElement(q.LocalName); + w.WriteStartElement(q.Prefix, q.LocalName, q.Namespace); foreach (var element in o) { var elementType = element.GetType(); @@ -125,31 +125,38 @@ public static IDecorator> AddEnumerableConverter(this IDecor var keyName = Decorator.Enclose(keyValue.ToString()).SanitizeXmlElementName(); if (Decorator.Enclose(valuePropertyType).IsComplex()) { - Decorator.Enclose(w).WriteObject(valueValue, valuePropertyType, opts => opts.Settings.RootName = new XmlQualifiedEntity(keyName)); + Decorator.Enclose(w).WriteObject(valueValue, valuePropertyType, opts => opts.Settings.RootName = new XmlQualifiedEntity(keyName, q.Namespace)); } else { - w.WriteElementString(keyName, Convert.ToString(valueValue, CultureInfo.InvariantCulture)); + w.WriteStartElement(keyName, q.Namespace); + w.WriteValue(valueValue); + w.WriteEndElement(); } } w.WriteEndElement(); } else { + var isDocumentRoot = w.WriteState == WriteState.Start; + if (isDocumentRoot) { w.WriteStartElement(q.Prefix, q.LocalName, q.Namespace); } + var qe = new XmlQualifiedEntity(q.Prefix, q.LocalName, q.Namespace); foreach (var item in o) { if (item == null) { continue; } var itemType = item.GetType(); if (Decorator.Enclose(itemType).IsComplex()) { - var localName = q.LocalName; - Decorator.Enclose(w).WriteObject(item, itemType, opts => opts.Settings.RootName = new XmlQualifiedEntity(localName)); + Decorator.Enclose(w).WriteObject(item, itemType, opts => opts.Settings.RootName = qe); } else { - w.WriteElementString(q.LocalName, Convert.ToString(item, CultureInfo.InvariantCulture)); + w.WriteStartElement(q.Prefix, q.LocalName, q.Namespace); + w.WriteValue(item); + w.WriteEndElement(); } } + if (isDocumentRoot) { w.WriteEndElement(); } } } else diff --git a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs index 0c53ec69e..7ea3beb10 100644 --- a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs +++ b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs @@ -129,9 +129,14 @@ internal XmlSerializerOptions RefreshWithConverterDependencies() _refreshed = true; if (Settings.FlattenCollectionItems) { - var existing = Decorator.Enclose(Settings.Converters).FirstOrDefaultWriterConverter(typeof(IEnumerable)); - if (existing != null) { Settings.Converters.Remove(existing); } - Decorator.Enclose(Settings.Converters).AddEnumerableConverter(flattenItems: true); + var converters = Decorator.Enclose(Settings.Converters); + while (true) + { + var existing = converters.FirstOrDefaultWriterConverter(typeof(IEnumerable)); + if (existing == null) { break; } + Settings.Converters.Remove(existing); + } + converters.AddEnumerableConverter(flattenItems: true); } Decorator.Enclose(Settings.Converters) .AddExceptionConverter(SensitivityDetails.HasFlag(FaultSensitivityDetails.StackTrace), SensitivityDetails.HasFlag(FaultSensitivityDetails.Data))