From d64c1171a364c7c857017e7efa300b4817ca9294 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 3 Jun 2026 09:33:02 +0200 Subject: [PATCH] Removed deprecated Protobuf separate project --- .../Protobuf/ProtobufMessageAccessor.cs | 530 ------------------ .../Protobuf/ProtobufMessageSerializer.cs | 53 -- .../CryptoExchange.Net.Protobuf.csproj | 47 -- .../CryptoExchange.Net.Protobuf.xml | 128 ----- CryptoExchange.Net.Protobuf/README.md | 52 -- 5 files changed, 810 deletions(-) delete mode 100644 CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageAccessor.cs delete mode 100644 CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageSerializer.cs delete mode 100644 CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj delete mode 100644 CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.xml delete mode 100644 CryptoExchange.Net.Protobuf/README.md diff --git a/CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageAccessor.cs b/CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageAccessor.cs deleted file mode 100644 index 98b5efb1..00000000 --- a/CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageAccessor.cs +++ /dev/null @@ -1,530 +0,0 @@ -using CryptoExchange.Net.Converters.MessageParsing; -using CryptoExchange.Net.Interfaces; -using CryptoExchange.Net.Objects; -using ProtoBuf; -using ProtoBuf.Meta; -using System; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Runtime.InteropServices.ComTypes; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; - -namespace CryptoExchange.Net.Converters.Protobuf -{ - /// - /// System.Text.Json message accessor - /// -#if NET5_0_OR_GREATER - public abstract class ProtobufMessageAccessor< - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] - TIntermediateType> : IMessageAccessor -#else - public abstract class ProtobufMessageAccessor : IMessageAccessor -#endif - { - /// - /// The intermediate deserialization object - /// - protected TIntermediateType? _intermediateType; - /// - /// Runtime type model - /// - protected RuntimeTypeModel _model; - - /// - public bool IsValid { get; set; } - - /// - public abstract bool OriginalDataAvailable { get; } - - /// - public object? Underlying => _intermediateType; - - /// - /// ctor - /// - public ProtobufMessageAccessor(RuntimeTypeModel model) - { - _model = model; - } - - /// - public NodeType? GetNodeType() - { - throw new NotImplementedException(); - } - - /// - public NodeType? GetNodeType(MessagePath path) - { - if (_intermediateType == null) - throw new InvalidOperationException("Data not read"); - - object? value = _intermediateType; - foreach (var step in path) - { - if (value == null) - break; - - if (step.Type == 0) - { - // array index - } - else if (step.Type == 1) - { - // property value -#pragma warning disable IL2075 // Type is already annotated - value = value.GetType().GetProperty(step.Property!)?.GetValue(value); -#pragma warning restore - } - else - { - // property name - } - } - - if (value == null) - return null; - - var valueType = value.GetType(); - if (valueType.IsArray) - return NodeType.Array; - - if (IsSimple(valueType)) - return NodeType.Value; - - return NodeType.Object; - } - - private static bool IsSimple(Type type) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // nullable type, check if the nested type is simple. - return IsSimple(type.GetGenericArguments()[0]); - } - return type.IsPrimitive - || type.IsEnum - || type == typeof(string) - || type == typeof(decimal); - } - - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2075:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif - public T? GetValue(MessagePath path) - { - if (_intermediateType == null) - throw new InvalidOperationException("Data not read"); - - object? value = _intermediateType; - foreach(var step in path) - { - if (value == null) - break; - - if (step.Type == 0) - { - // array index - } - else if (step.Type == 1) - { - // property value -#pragma warning disable IL2075 // Type is already annotated - value = value.GetType().GetProperty(step.Property!)?.GetValue(value); -#pragma warning restore - } - else - { - // property name - } - } - - return (T?)value; - } - - /// - public T?[]? GetValues(MessagePath path) - { - throw new NotImplementedException(); - } - - /// - public abstract string GetOriginalString(); - - /// - public abstract void Clear(); - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif - public abstract CallResult Deserialize( -#if NET5_0_OR_GREATER - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - Type type, MessagePath? path = null); - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif - public abstract CallResult Deserialize< -#if NET5_0_OR_GREATER - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - T>(MessagePath? path = null); - } - - /// - /// System.Text.Json stream message accessor - /// - public class ProtobufStreamMessageAccessor< -#if NET5_0_OR_GREATER - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - TIntermediate> : ProtobufMessageAccessor, IStreamMessageAccessor - { - private Stream? _stream; - - /// - public override bool OriginalDataAvailable => _stream?.CanSeek == true; - - /// - /// ctor - /// - public ProtobufStreamMessageAccessor(RuntimeTypeModel model) : base(model) - { - } - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif - public override CallResult Deserialize( -#if NET5_0_OR_GREATER - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - Type type, MessagePath? path = null) - { - try - { - var result = _model.Deserialize(type, _stream); - return new CallResult(result); - } - catch (Exception ex) - { - return new CallResult(new DeserializeError("Protobuf deserialization failed: " + ex.Message, ex)); - } - } - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif - public override CallResult Deserialize< -#if NET5_0_OR_GREATER - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - T>(MessagePath? path = null) - { - try - { - var result = _model.Deserialize(_stream); - return new CallResult(result); - } - catch(Exception ex) - { - return new CallResult(new DeserializeError("Protobuf deserialization failed: " + ex.Message, ex)); - } - } - - /// - public Task Read(Stream stream, bool bufferStream) - { - if (bufferStream && stream is not MemoryStream) - { - // We need to be buffer the stream, and it's not currently a seekable stream, so copy it to a new memory stream - _stream = new MemoryStream(); - stream.CopyTo(_stream); - _stream.Position = 0; - } - else if (bufferStream) - { - // We need to buffer the stream, and the current stream is seekable, store as is - _stream = stream; - } - else - { - // We don't need to buffer the stream, so don't bother keeping the reference - } - - try - { - _intermediateType = _model.Deserialize(_stream); - IsValid = true; - return Task.FromResult(CallResult.SuccessResult); - } - catch (Exception ex) - { - // Not a json message - IsValid = false; - return Task.FromResult(new CallResult(new DeserializeError("Protobuf deserialization failed: " + ex.Message, ex))); - } - } - - /// - public override string GetOriginalString() - { - if (_stream is null) - throw new NullReferenceException("Stream not initialized"); - - _stream.Position = 0; - using var textReader = new StreamReader(_stream, Encoding.UTF8, false, 1024, true); - return textReader.ReadToEnd(); - } - - /// - public override void Clear() - { - _stream?.Dispose(); - _stream = null; - _intermediateType = default; - } - - } - - /// - /// Protobuf byte message accessor - /// - public class ProtobufByteMessageAccessor< -#if NET5_0_OR_GREATER - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - TIntermediate> : ProtobufMessageAccessor, IByteMessageAccessor - { - private ReadOnlyMemory _bytes; - - /// - /// ctor - /// - public ProtobufByteMessageAccessor(RuntimeTypeModel model) : base(model) - { - } - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif - public override CallResult Deserialize( - -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] -#endif - Type type, MessagePath? path = null) - { - try - { - using var stream = new MemoryStream(_bytes.ToArray()); - stream.Position = 0; - var result = _model.Deserialize(type, stream); - return new CallResult(result); - } - catch (Exception ex) - { - return new CallResult(new DeserializeError("Protobuf deserialization failed: " + ex.Message, ex)); - } - } - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif -#if NET5_0_OR_GREATER - public override CallResult Deserialize< - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] - T>(MessagePath? path = null) -#else - public override CallResult Deserialize(MessagePath? path = null) -#endif - { - try - { - var result = _model.Deserialize(_bytes); - return new CallResult(result); - } - catch (Exception ex) - { - return new CallResult(new DeserializeError("Protobuf deserialization failed: " + ex.Message, ex)); - } - } - - /// - public CallResult Read(ReadOnlyMemory data) - { - _bytes = data; - - try - { - _intermediateType = _model.Deserialize(data); - IsValid = true; - return CallResult.SuccessResult; - } - catch (Exception ex) - { - // Not a json message - IsValid = false; - return new CallResult(new DeserializeError("Protobuf deserialization failed: " + ex.Message, ex)); - } - } - - /// - public override string GetOriginalString() => - // NetStandard 2.0 doesn't support GetString from a ReadonlySpan, so use ToArray there instead -#if NETSTANDARD2_0 - Encoding.UTF8.GetString(_bytes.ToArray()); -#else - Encoding.UTF8.GetString(_bytes.Span); -#endif - - /// - public override bool OriginalDataAvailable => true; - - /// - public override void Clear() - { - _bytes = null; - _intermediateType = default; - } - } -} \ No newline at end of file diff --git a/CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageSerializer.cs b/CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageSerializer.cs deleted file mode 100644 index 80df7371..00000000 --- a/CryptoExchange.Net.Protobuf/Converters/Protobuf/ProtobufMessageSerializer.cs +++ /dev/null @@ -1,53 +0,0 @@ -using CryptoExchange.Net.Interfaces; -using ProtoBuf.Meta; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Reflection; - -namespace CryptoExchange.Net.Converters.Protobuf -{ - /// - public class ProtobufMessageSerializer : IByteMessageSerializer - { - private RuntimeTypeModel _model; - - /// - /// ctor - /// - public ProtobufMessageSerializer(RuntimeTypeModel model) - { - _model = model; - } - - /// -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2092:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] - [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2095:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")] -#endif -#if NET5_0_OR_GREATER - public byte[] Serialize< - [DynamicallyAccessedMembers( -#if NET8_0_OR_GREATER - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.NonPublicNestedTypes | - DynamicallyAccessedMemberTypes.PublicProperties | - DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | -#endif - DynamicallyAccessedMemberTypes.PublicNestedTypes | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicMethods - )] - T>(T message) -#else - public byte[] Serialize(T message) -#endif - { - using var memoryStream = new MemoryStream(); - _model.Serialize(memoryStream, message); - return memoryStream.ToArray(); - } - } -} diff --git a/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj b/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj deleted file mode 100644 index 8b20948d..00000000 --- a/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.csproj +++ /dev/null @@ -1,47 +0,0 @@ - - - netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0 - - - CryptoExchange.Net.Protobuf - JKorf - Protobuf support for CryptoExchange.Net - 10.0.1 - 10.0.1 - 10.0.1 - false - CryptoExchange;CryptoExchange.Net - git - https://github.com/JKorf/CryptoExchange.Net.git - https://github.com/JKorf/CryptoExchange.Net/tree/master/CryptoExchange.Net.Protobuf - en - README.md - icon.png - true - https://github.com/JKorf/CryptoExchange.Net?tab=readme-ov-file#release-notes - enable - 12.0 - MIT - - - - - - - true - - - true - true - snupkg - true - true - - - CryptoExchange.Net.Protobuf.xml - - - - - - \ No newline at end of file diff --git a/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.xml b/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.xml deleted file mode 100644 index 0b7b110f..00000000 --- a/CryptoExchange.Net.Protobuf/CryptoExchange.Net.Protobuf.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - CryptoExchange.Net.Protobuf - - - - - System.Text.Json message accessor - - - - - The intermediate deserialization object - - - - - Runtime type model - - - - - - - - - - - - - - ctor - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System.Text.Json stream message accessor - - - - - - - - ctor - - - - - - - - - - - - - - - - - - - - Protobuf byte message accessor - - - - - ctor - - - - - - - - - - - - - - - - - - - - - - - - - - ctor - - - - - - - diff --git a/CryptoExchange.Net.Protobuf/README.md b/CryptoExchange.Net.Protobuf/README.md deleted file mode 100644 index a1cbb762..00000000 --- a/CryptoExchange.Net.Protobuf/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# ![.CryptoExchange.Net](https://github.com/JKorf/CryptoExchange.Net/blob/ffcb7db8ff597c2f14982d68464015a748815580/CryptoExchange.Net/Icon/icon.png) CryptoExchange.Net.Proto - -[![.NET](https://img.shields.io/github/actions/workflow/status/JKorf/CryptoExchange.Net/dotnet.yml?style=for-the-badge)](https://github.com/JKorf/CryptoExchange.Net/actions/workflows/dotnet.yml) [![Nuget downloads](https://img.shields.io/nuget/dt/CryptoExchange.Net.Protobuf.svg?style=for-the-badge)](https://www.nuget.org/packages/CryptoExchange.Net.Protobuf) ![License](https://img.shields.io/github/license/JKorf/CryptoExchange.Net?style=for-the-badge) - -Protobuf support for CryptoExchange.Net. - -## Release notes -* Version 10.0.1 - 16 Dec 2025 - * Updated CryptoExchange.Net version to 10.0.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 10.0.0 - 16 Dec 2025 - * Updated CryptoExchange.Net version to 10.0.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.13.0 - 10 Nov 2025 - * Updated CryptoExchange.Net version to 9.13.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.12.0 - 03 Nov 2025 - * Updated CryptoExchange.Net version to 9.12.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.11.1 - 30 Oct 2025 - * Updated CryptoExchange.Net version to 9.11.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.11.0 - 30 Oct 2025 - * Updated CryptoExchange.Net version to 9.11.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.10.0 - 15 Oct 2025 - * Updated CryptoExchange.Net version to 9.10.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.9.0 - 06 Oct 2025 - * Updated CryptoExchange.Net version to 9.9.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.8.0 - 30 Sep 2025 - * Updated CryptoExchange.Net version to 9.8.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.7.0 - 01 Sep 2025 - * Updated CryptoExchange.Net version to 9.7.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.6.0 - 25 Aug 2025 - * Updated CryptoExchange.Net version to 9.6.0 - -* Version 9.5.0 - 19 Aug 2025 - * Updated CryptoExchange.Net version to 9.5.0 - -* Version 9.4.0 - 04 Aug 2025 - * Updated CryptoExchange.Net to version 9.4.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - * Updated protobuf-net package version to 3.2.56 - -* Version 9.3.0 - 23 Jul 2025 - * Updated CryptoExchange.Net to version 9.3.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ - -* Version 9.2.0 - 14 Jul 2025 - * Initial release