Skip to content

Commit 0cdb254

Browse files
committed
[DEVEX-222] Added XML documentation for Serialization settings
1 parent 95f8546 commit 0cdb254

File tree

6 files changed

+313
-22
lines changed

6 files changed

+313
-22
lines changed

src/Kurrent.Client/Core/KurrentClientSerializationSettings.cs

Lines changed: 228 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,74 @@
33

44
namespace EventStore.Client;
55

6-
public enum AutomaticDeserialization {
7-
Disabled = 0,
8-
Enabled = 1
9-
}
10-
6+
/// <summary>
7+
/// Provides configuration options for messages serialization and deserialization in the KurrentDB client.
8+
/// </summary>
119
public class KurrentClientSerializationSettings {
12-
public ISerializer? JsonSerializer { get; set; }
13-
public ISerializer? BytesSerializer { get; set; }
14-
public ContentType DefaultContentType { get; set; } = ContentType.Json;
10+
/// <summary>
11+
/// The serializer responsible for handling JSON-formatted data. This serializer is used both for
12+
/// serializing outgoing JSON messages and deserializing incoming JSON messages. If not specified,
13+
/// a default System.Text.Json serializer will be used with standard settings.
14+
/// <br/>
15+
/// That also allows you to bring your custom JSON serializer implementation (e.g. JSON.NET)
16+
/// </summary>
17+
public ISerializer? JsonSerializer { get; set; }
18+
19+
/// <summary>
20+
/// The serializer responsible for handling binary data formats. This is used when working with
21+
/// binary-encoded messages rather than text-based formats (e.g. Protobuf or Avro). Required when storing
22+
/// or retrieving content with "application/octet-stream" content type
23+
/// </summary>
24+
public ISerializer? BytesSerializer { get; set; }
25+
26+
/// <summary>
27+
/// Determines which serialization format (JSON or binary) is used by default when writing messages
28+
/// where the content type isn't explicitly specified. The default content type is "application/json"
29+
/// </summary>
30+
public ContentType DefaultContentType { get; set; } = ContentType.Json;
31+
32+
/// <summary>
33+
/// Defines the custom strategy used to map between the type name stored in messages and .NET type names.
34+
/// If not provided the default <see cref="Kurrent.Client.Core.Serialization.DefaultMessageTypeNamingStrategy"/> will be used.
35+
/// It resolves the CLR type name to the format: "{stream category name}-{CLR Message Type}".
36+
/// You can provide your own implementation of <see cref="Kurrent.Client.Core.Serialization.IMessageTypeNamingStrategy"/>
37+
/// and register it here to override the default behaviour
38+
/// </summary>
1539
public IMessageTypeNamingStrategy? MessageTypeNamingStrategy { get; set; }
16-
public IDictionary<Type, string> MessageTypeMap { get; set; } = new Dictionary<Type, string>();
17-
public IDictionary<string, Type[]> CategoryMessageTypesMap { get; set; } = new Dictionary<string, Type[]>();
18-
public Type? DefaultMetadataType { get; set; }
1940

41+
/// <summary>
42+
/// Allows to register mapping of CLR message types to their corresponding message type names used in serialized messages.
43+
/// </summary>
44+
public IDictionary<Type, string> MessageTypeMap { get; set; } = new Dictionary<Type, string>();
45+
46+
/// <summary>
47+
/// Registers CLR message types that can be appended to the specific stream category.
48+
/// Types will have message type names resolved based on the used <see cref="Kurrent.Client.Core.Serialization.IMessageTypeNamingStrategy"/>
49+
/// </summary>
50+
public IDictionary<string, Type[]> CategoryMessageTypesMap { get; set; } = new Dictionary<string, Type[]>();
51+
52+
/// <summary>
53+
/// Specifies the CLR type that should be used when deserializing metadata for all events.
54+
/// When set, the client will attempt to deserialize event metadata into this type.
55+
/// If not provided, <see cref="Kurrent.Diagnostics.Tracing.TracingMetadata"/> will be used.
56+
/// </summary>
57+
public Type? DefaultMetadataType { get; set; }
58+
59+
/// <summary>
60+
/// Creates a new instance of serialization settings with either default values or custom configuration.
61+
/// This factory method is the recommended way to create serialization settings for the KurrentDB client.
62+
/// </summary>
63+
/// <param name="configure">Optional callback to customize the settings. If null, default settings are used.</param>
64+
/// <returns>A fully configured instance ready to be used with the KurrentDB client.</returns>
65+
/// <example>
66+
/// <code>
67+
/// var settings = KurrentClientSerializationSettings.Default(options => {
68+
/// options.RegisterMessageType&lt;UserCreated&gt;("user-created");
69+
/// options.RegisterMessageType&lt;UserUpdated&gt;("user-updated");
70+
/// options.RegisterMessageTypeForCategory&lt;UserCreated&gt;("user");
71+
/// });
72+
/// </code>
73+
/// </example>
2074
public static KurrentClientSerializationSettings Default(
2175
Action<KurrentClientSerializationSettings>? configure = null
2276
) {
@@ -27,6 +81,22 @@ public static KurrentClientSerializationSettings Default(
2781
return settings;
2882
}
2983

84+
/// <summary>
85+
/// Configures the JSON serializer using custom options while inheriting from the default System.Text.Json settings.
86+
/// This allows fine-tuning serialization behavior such as case sensitivity, property naming, etc.
87+
/// </summary>
88+
/// <param name="configure">A function that receives the default options and returns modified options.</param>
89+
/// <returns>The current instance for method chaining.</returns>
90+
/// <example>
91+
/// <code>
92+
/// settings.UseJsonSettings(options => {
93+
/// options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
94+
/// options.WriteIndented = true;
95+
/// options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
96+
/// return options;
97+
/// });
98+
/// </code>
99+
/// </example>
30100
public KurrentClientSerializationSettings UseJsonSettings(
31101
Func<JsonSerializerOptions, JsonSerializerOptions> configure
32102
) {
@@ -38,6 +108,11 @@ Func<JsonSerializerOptions, JsonSerializerOptions> configure
38108
return this;
39109
}
40110

111+
/// <summary>
112+
/// Configures JSON serialization using provided System.Text.Json serializer options.
113+
/// </summary>
114+
/// <param name="systemTextJsonSerializerOptions">The JSON serializer options to use.</param>
115+
/// <returns>The current instance for method chaining.</returns>
41116
public KurrentClientSerializationSettings UseJsonSettings(JsonSerializerOptions systemTextJsonSerializerOptions) {
42117
JsonSerializer = new SystemTextJsonSerializer(
43118
new SystemTextJsonSerializationSettings { Options = systemTextJsonSerializerOptions }
@@ -46,6 +121,11 @@ public KurrentClientSerializationSettings UseJsonSettings(JsonSerializerOptions
46121
return this;
47122
}
48123

124+
/// <summary>
125+
/// Configures JSON serialization using provided <see cref="Kurrent.Client.Core.Serialization.SystemTextJsonSerializationSettings"/>
126+
/// </summary>
127+
/// <param name="jsonSerializationSettings">The SystemTextJson serialization settings to use.</param>
128+
/// <returns>The current instance for method chaining.</returns>
49129
public KurrentClientSerializationSettings UseJsonSettings(
50130
SystemTextJsonSerializationSettings jsonSerializationSettings
51131
) {
@@ -54,22 +134,44 @@ SystemTextJsonSerializationSettings jsonSerializationSettings
54134
return this;
55135
}
56136

137+
/// <summary>
138+
/// Sets a custom JSON serializer implementation.
139+
/// That also allows you to bring your custom JSON serializer implementation (e.g. JSON.NET)
140+
/// </summary>
141+
/// <param name="serializer">The serializer to use for JSON content.</param>
142+
/// <returns>The current instance for method chaining.</returns>
57143
public KurrentClientSerializationSettings UseJsonSerializer(ISerializer serializer) {
58144
JsonSerializer = serializer;
59145

60146
return this;
61147
}
62148

149+
/// <summary>
150+
/// Sets a custom binary serializer implementation.
151+
/// That also allows you to bring your custom binary serializer implementation (e.g. Protobuf or Avro)
152+
/// </summary>
153+
/// <param name="serializer">The serializer to use for binary content.</param>
154+
/// <returns>The current instance for method chaining.</returns>
63155
public KurrentClientSerializationSettings UseBytesSerializer(ISerializer serializer) {
64156
BytesSerializer = serializer;
65157

66158
return this;
67159
}
68160

161+
/// <summary>
162+
/// Configures a custom message type naming strategy.
163+
/// </summary>
164+
/// <typeparam name="TCustomMessageTypeResolutionStrategy">The type of naming strategy to use.</typeparam>
165+
/// <returns>The current instance for method chaining.</returns>
69166
public KurrentClientSerializationSettings UseMessageTypeNamingStrategy<TCustomMessageTypeResolutionStrategy>()
70167
where TCustomMessageTypeResolutionStrategy : IMessageTypeNamingStrategy, new() =>
71168
UseMessageTypeNamingStrategy(new TCustomMessageTypeResolutionStrategy());
72169

170+
/// <summary>
171+
/// Configures a custom message type naming strategy.
172+
/// </summary>
173+
/// <param name="messageTypeNamingStrategy">The naming strategy instance to use.</param>
174+
/// <returns>The current instance for method chaining.</returns>
73175
public KurrentClientSerializationSettings UseMessageTypeNamingStrategy(
74176
IMessageTypeNamingStrategy messageTypeNamingStrategy
75177
) {
@@ -78,9 +180,31 @@ IMessageTypeNamingStrategy messageTypeNamingStrategy
78180
return this;
79181
}
80182

183+
/// <summary>
184+
/// Associates a message type with a specific stream category to enable automatic deserialization.
185+
/// In event sourcing, streams are often prefixed with a category (e.g., "user-123", "order-456").
186+
/// This method tells the client which message types can appear in streams of a given category.
187+
/// </summary>
188+
/// <typeparam name="T">The event or message type that can appear in the category's streams.</typeparam>
189+
/// <param name="categoryName">The category prefix (e.g., "user", "order", "account").</param>
190+
/// <returns>The current instance for method chaining.</returns>
191+
/// <example>
192+
/// <code>
193+
/// // Register event types that can appear in user streams
194+
/// settings.RegisterMessageTypeForCategory&lt;UserCreated&gt;("user")
195+
/// .RegisterMessageTypeForCategory&lt;UserUpdated&gt;("user")
196+
/// .RegisterMessageTypeForCategory&lt;UserDeleted&gt;("user");
197+
/// </code>
198+
/// </example>
81199
public KurrentClientSerializationSettings RegisterMessageTypeForCategory<T>(string categoryName) =>
82200
RegisterMessageTypeForCategory(categoryName, typeof(T));
83201

202+
/// <summary>
203+
/// Registers multiple message types for a specific stream category.
204+
/// </summary>
205+
/// <param name="categoryName">The category name to register the types with.</param>
206+
/// <param name="types">The message types to register.</param>
207+
/// <returns>The current instance for method chaining.</returns>
84208
public KurrentClientSerializationSettings RegisterMessageTypeForCategory(string categoryName, params Type[] types) {
85209
CategoryMessageTypesMap[categoryName] = CategoryMessageTypesMap.TryGetValue(categoryName, out var current)
86210
? [..current, ..types]
@@ -89,15 +213,45 @@ public KurrentClientSerializationSettings RegisterMessageTypeForCategory(string
89213
return this;
90214
}
91215

216+
/// <summary>
217+
/// Maps a .NET type to a specific message type name that will be stored in the message metadata.
218+
/// This mapping is used during automatic deserialization, as it tells the client which CLR type
219+
/// to instantiate when encountering a message with a particular type name in the database.
220+
/// </summary>
221+
/// <typeparam name="T">The .NET type to register (typically a message class).</typeparam>
222+
/// <param name="typeName">The string identifier to use for this type in the database.</param>
223+
/// <returns>The current instance for method chaining.</returns>
224+
/// <remarks>
225+
/// The type name is often different from the .NET type name to support versioning and evolution
226+
/// of your domain model without breaking existing stored messages.
227+
/// </remarks>
228+
/// <example>
229+
/// <code>
230+
/// // Register me types with their corresponding type identifiers
231+
/// settings.RegisterMessageType&lt;UserCreated&gt;("user-created-v1")
232+
/// .RegisterMessageType&lt;OrderPlaced&gt;("order-placed-v2");
233+
/// </code>
234+
/// </example>
92235
public KurrentClientSerializationSettings RegisterMessageType<T>(string typeName) =>
93236
RegisterMessageType(typeof(T), typeName);
94237

238+
/// <summary>
239+
/// Registers a message type with a specific type name.
240+
/// </summary>
241+
/// <param name="type">The message type to register.</param>
242+
/// <param name="typeName">The type name to register for the message type.</param>
243+
/// <returns>The current instance for method chaining.</returns>
95244
public KurrentClientSerializationSettings RegisterMessageType(Type type, string typeName) {
96245
MessageTypeMap[type] = typeName;
97246

98247
return this;
99248
}
100249

250+
/// <summary>
251+
/// Registers multiple message types with their corresponding type names.
252+
/// </summary>
253+
/// <param name="typeMap">Dictionary mapping types to their type names.</param>
254+
/// <returns>The current instance for method chaining.</returns>
101255
public KurrentClientSerializationSettings RegisterMessageTypes(IDictionary<Type, string> typeMap) {
102256
foreach (var map in typeMap) {
103257
MessageTypeMap[map.Key] = map.Value;
@@ -106,15 +260,31 @@ public KurrentClientSerializationSettings RegisterMessageTypes(IDictionary<Type,
106260
return this;
107261
}
108262

263+
/// <summary>
264+
/// Configures a strongly-typed metadata class for all mes in the system.
265+
/// This enables accessing metadata properties in a type-safe manner rather than using dynamic objects.
266+
/// </summary>
267+
/// <typeparam name="T">The metadata class type containing properties matching the expected metadata fields.</typeparam>
268+
/// <returns>The current instance for method chaining.</returns>
109269
public KurrentClientSerializationSettings UseMetadataType<T>() =>
110270
UseMetadataType(typeof(T));
111271

272+
/// <summary>
273+
/// Configures a strongly-typed metadata class for all mes in the system.
274+
/// This enables accessing metadata properties in a type-safe manner rather than using dynamic objects.
275+
/// </summary>
276+
/// <param name="type">The metadata class type containing properties matching the expected metadata fields.</param>
277+
/// <returns>The current instance for method chaining.</returns>
112278
public KurrentClientSerializationSettings UseMetadataType(Type type) {
113279
DefaultMetadataType = type;
114280

115281
return this;
116282
}
117283

284+
/// <summary>
285+
/// Creates a deep copy of the current serialization settings.
286+
/// </summary>
287+
/// <returns>A new instance with copied settings.</returns>
118288
internal KurrentClientSerializationSettings Clone() {
119289
return new KurrentClientSerializationSettings {
120290
BytesSerializer = BytesSerializer,
@@ -127,17 +297,64 @@ internal KurrentClientSerializationSettings Clone() {
127297
}
128298
}
129299

300+
/// <summary>
301+
/// Provides operation-specific serialization settings that override the global client configuration
302+
/// for individual operations like reading from or appending to streams. This allows fine-tuning
303+
/// serialization behavior on a per-operation basis without changing the client-wide settings.
304+
/// </summary>
130305
public class OperationSerializationSettings {
306+
/// <summary>
307+
/// Controls whether mes should be automatically deserialized for this specific operation.
308+
/// When enabled (the default), messages will be converted to their appropriate CLR types.
309+
/// When disabled, messages will be returned in their raw serialized form.
310+
/// </summary>
131311
public AutomaticDeserialization AutomaticDeserialization { get; private set; } = AutomaticDeserialization.Enabled;
312+
313+
/// <summary>
314+
/// A callback that allows customizing serialization settings for this specific operation.
315+
/// This can be used to override type mappings, serializers, or other settings just for
316+
/// the scope of a single operation without affecting other operations.
317+
/// </summary>
132318
public Action<KurrentClientSerializationSettings>? ConfigureSettings { get; private set; }
133319

320+
/// <summary>
321+
/// A pre-configured settings instance that disables automatic deserialization.
322+
/// Use this when you need to access raw message data in its serialized form.
323+
/// </summary>
134324
public static readonly OperationSerializationSettings Disabled = new OperationSerializationSettings {
135325
AutomaticDeserialization = AutomaticDeserialization.Disabled
136326
};
137327

328+
/// <summary>
329+
/// Creates operation-specific serialization settings with custom configuration while keeping
330+
/// automatic deserialization enabled. This allows operation-specific type mappings or
331+
/// serializer settings without changing the global client configuration.
332+
/// </summary>
333+
/// <param name="configure">A callback to customize serialization settings for this operation.</param>
334+
/// <returns>A configured instance of <see cref="OperationSerializationSettings"/> with enabled deserialization.</returns>
138335
public static OperationSerializationSettings Configure(Action<KurrentClientSerializationSettings> configure) =>
139336
new OperationSerializationSettings {
140337
AutomaticDeserialization = AutomaticDeserialization.Enabled,
141338
ConfigureSettings = configure
142339
};
143340
}
341+
342+
/// <summary>
343+
/// Controls whether the KurrentDB client should automatically deserialize message payloads
344+
/// into their corresponding CLR types based on the configured type mappings.
345+
/// </summary>
346+
public enum AutomaticDeserialization {
347+
/// <summary>
348+
/// Disables automatic deserialization. Messages will be returned in their raw serialized form,
349+
/// requiring manual deserialization by the application. Use this when you need direct access to the raw data
350+
/// or when working with messages that don't have registered type mappings.
351+
/// </summary>
352+
Disabled = 0,
353+
354+
/// <summary>
355+
/// Enables automatic deserialization. The client will attempt to convert messages into their appropriate
356+
/// CLR types using the configured serializers and type mappings. This simplifies working with strongly-typed
357+
/// domain messages but requires proper type registration.
358+
/// </summary>
359+
Enabled = 1
360+
}

src/Kurrent.Client/Core/KurrentClientSettings.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ public partial class KurrentClientSettings {
5858
/// </summary>
5959
public TimeSpan? DefaultDeadline { get; set; } = TimeSpan.FromSeconds(10);
6060

61+
/// <summary>
62+
/// Provides configuration options for messages serialization and deserialization in the KurrentDB client.
63+
/// If null, default settings are used.
64+
/// </summary>
6165
public KurrentClientSerializationSettings Serialization { get; set; } = KurrentClientSerializationSettings.Default();
6266
}
6367
}

src/Kurrent.Client/Core/ResolvedEvent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public ResolvedEvent(EventRecord @event, EventRecord? link, ulong? commitPositio
9696
: new Position?();
9797
}
9898

99-
public static ResolvedEvent From(
99+
internal static ResolvedEvent From(
100100
EventRecord @event,
101101
EventRecord? link,
102102
ulong? commitPosition,

0 commit comments

Comments
 (0)