Skip to content

Commit df6eb65

Browse files
Copilotjaviercn
andcommitted
Move PersistAsync and TryTake methods to PersistentStateValueProvider per code review feedback
Co-authored-by: javiercn <[email protected]>
1 parent 4c3dcac commit df6eb65

File tree

5 files changed

+57
-60
lines changed

5 files changed

+57
-60
lines changed

src/Components/Components/src/IPersistentComponentStateSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Components;
88
/// <summary>
99
/// Provides custom serialization logic for persistent component state values.
1010
/// </summary>
11-
internal interface IPersistentComponentStateSerializer
11+
public interface IPersistentComponentStateSerializer
1212
{
1313
/// <summary>
1414
/// Serializes the provided <paramref name="value"/> and writes it to the <paramref name="writer"/>.

src/Components/Components/src/PersistentComponentState.cs

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Buffers;
54
using System.Diagnostics.CodeAnalysis;
65
using System.Text.Json;
76
using static Microsoft.AspNetCore.Internal.LinkerFlags;
@@ -133,33 +132,6 @@ internal void PersistAsBytes(string key, byte[] data)
133132
_currentState.Add(key, data);
134133
}
135134

136-
/// <summary>
137-
/// Serializes <paramref name="instance"/> using the provided <paramref name="serializer"/> and persists it under the given <paramref name="key"/>.
138-
/// </summary>
139-
/// <typeparam name="TValue">The <paramref name="instance"/> type.</typeparam>
140-
/// <param name="key">The key to use to persist the state.</param>
141-
/// <param name="instance">The instance to persist.</param>
142-
/// <param name="serializer">The custom serializer to use for serialization.</param>
143-
internal async Task PersistAsync<TValue>(string key, TValue instance, IPersistentComponentStateSerializer<TValue> serializer)
144-
{
145-
ArgumentNullException.ThrowIfNull(key);
146-
ArgumentNullException.ThrowIfNull(serializer);
147-
148-
if (!PersistingState)
149-
{
150-
throw new InvalidOperationException("Persisting state is only allowed during an OnPersisting callback.");
151-
}
152-
153-
if (_currentState.ContainsKey(key))
154-
{
155-
throw new ArgumentException($"There is already a persisted object under the same key '{key}'");
156-
}
157-
158-
using var writer = new PooledArrayBufferWriter<byte>();
159-
await serializer.PersistAsync(instance, writer);
160-
_currentState.Add(key, writer.WrittenMemory.ToArray());
161-
}
162-
163135
/// <summary>
164136
/// Tries to retrieve the persisted state as JSON with the given <paramref name="key"/> and deserializes it into an
165137
/// instance of type <typeparamref name="TValue"/>.
@@ -205,34 +177,6 @@ internal bool TryTakeFromJson(string key, [DynamicallyAccessedMembers(JsonSerial
205177
}
206178
}
207179

208-
/// <summary>
209-
/// Tries to retrieve the persisted state with the given <paramref name="key"/> and deserializes it using the provided <paramref name="serializer"/> into an
210-
/// instance of type <typeparamref name="TValue"/>.
211-
/// When the key is present, the state is successfully returned via <paramref name="instance"/>
212-
/// and removed from the <see cref="PersistentComponentState"/>.
213-
/// </summary>
214-
/// <param name="key">The key used to persist the instance.</param>
215-
/// <param name="serializer">The custom serializer to use for deserialization.</param>
216-
/// <param name="instance">The persisted instance.</param>
217-
/// <returns><c>true</c> if the state was found; <c>false</c> otherwise.</returns>
218-
internal bool TryTake<TValue>(string key, IPersistentComponentStateSerializer<TValue> serializer, [MaybeNullWhen(false)] out TValue instance)
219-
{
220-
ArgumentNullException.ThrowIfNull(key);
221-
ArgumentNullException.ThrowIfNull(serializer);
222-
223-
if (TryTake(key, out var data))
224-
{
225-
var sequence = new ReadOnlySequence<byte>(data!);
226-
instance = serializer.Restore(sequence);
227-
return true;
228-
}
229-
else
230-
{
231-
instance = default;
232-
return false;
233-
}
234-
}
235-
236180
/// <summary>
237181
/// Tries to retrieve the persisted state as raw bytes with the given <paramref name="key"/>.
238182
/// When the key is present, the raw bytes are successfully returned via <paramref name="data"/>

src/Components/Components/src/PersistentStateValueProvider.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,4 +321,49 @@ private static bool IsSerializableKey(object key)
321321

322322
return result;
323323
}
324+
325+
/// <summary>
326+
/// Serializes <paramref name="instance"/> using the provided <paramref name="serializer"/> and persists it under the given <paramref name="key"/>.
327+
/// </summary>
328+
/// <typeparam name="TValue">The <paramref name="instance"/> type.</typeparam>
329+
/// <param name="key">The key to use to persist the state.</param>
330+
/// <param name="instance">The instance to persist.</param>
331+
/// <param name="serializer">The custom serializer to use for serialization.</param>
332+
internal async Task PersistAsync<TValue>(string key, TValue instance, IPersistentComponentStateSerializer<TValue> serializer)
333+
{
334+
ArgumentNullException.ThrowIfNull(key);
335+
ArgumentNullException.ThrowIfNull(serializer);
336+
337+
using var writer = new PooledArrayBufferWriter<byte>();
338+
await serializer.PersistAsync(instance, writer);
339+
state.PersistAsBytes(key, writer.WrittenMemory.ToArray());
340+
}
341+
342+
/// <summary>
343+
/// Tries to retrieve the persisted state with the given <paramref name="key"/> and deserializes it using the provided <paramref name="serializer"/> into an
344+
/// instance of type <typeparamref name="TValue"/>.
345+
/// When the key is present, the state is successfully returned via <paramref name="instance"/>
346+
/// and removed from the <see cref="PersistentComponentState"/>.
347+
/// </summary>
348+
/// <param name="key">The key used to persist the instance.</param>
349+
/// <param name="serializer">The custom serializer to use for deserialization.</param>
350+
/// <param name="instance">The persisted instance.</param>
351+
/// <returns><c>true</c> if the state was found; <c>false</c> otherwise.</returns>
352+
internal bool TryTake<TValue>(string key, IPersistentComponentStateSerializer<TValue> serializer, [MaybeNullWhen(false)] out TValue instance)
353+
{
354+
ArgumentNullException.ThrowIfNull(key);
355+
ArgumentNullException.ThrowIfNull(serializer);
356+
357+
if (state.TryTakeBytes(key, out var data))
358+
{
359+
var sequence = new ReadOnlySequence<byte>(data!);
360+
instance = serializer.Restore(sequence);
361+
return true;
362+
}
363+
else
364+
{
365+
instance = default;
366+
return false;
367+
}
368+
}
324369
}

src/Components/Components/src/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ Microsoft.AspNetCore.Components.Infrastructure.RegisterPersistentComponentStateS
1616
Microsoft.AspNetCore.Components.PersistentStateAttribute
1717
Microsoft.AspNetCore.Components.PersistentStateAttribute.PersistentStateAttribute() -> void
1818
Microsoft.AspNetCore.Components.Infrastructure.PersistentStateProviderServiceCollectionExtensions
19+
Microsoft.AspNetCore.Components.IPersistentComponentStateSerializer
20+
Microsoft.AspNetCore.Components.IPersistentComponentStateSerializer.PersistAsync(System.Type! type, object! value, System.Buffers.IBufferWriter<byte>! writer) -> System.Threading.Tasks.Task!
21+
Microsoft.AspNetCore.Components.IPersistentComponentStateSerializer.Restore(System.Type! type, System.Buffers.ReadOnlySequence<byte> data) -> object!
1922
Microsoft.AspNetCore.Components.IPersistentComponentStateSerializer<T>
2023
Microsoft.AspNetCore.Components.IPersistentComponentStateSerializer<T>.PersistAsync(T value, System.Buffers.IBufferWriter<byte>! writer) -> System.Threading.Tasks.Task!
2124
Microsoft.AspNetCore.Components.IPersistentComponentStateSerializer<T>.Restore(System.Buffers.ReadOnlySequence<byte> data) -> T

src/Components/Components/test/IPersistentComponentStateSerializerTests.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,25 @@ public async Task PersistAsync_CanUseCustomSerializer()
1717
// Arrange
1818
var currentState = new Dictionary<string, byte[]>();
1919
var state = new PersistentComponentState(currentState, []);
20+
var serviceProvider = new ServiceCollection().BuildServiceProvider();
21+
var stateValueProvider = new PersistentStateValueProvider(state, serviceProvider);
2022
var customSerializer = new TestStringSerializer();
2123
var testValue = "Hello, World!";
2224

2325
state.PersistingState = true;
2426

2527
// Act
26-
await state.PersistAsync("test-key", testValue, customSerializer);
28+
await stateValueProvider.PersistAsync("test-key", testValue, customSerializer);
2729

2830
// Assert
2931
state.PersistingState = false;
3032

3133
// Simulate the state transfer that happens between persist and restore phases
3234
var newState = new PersistentComponentState(new Dictionary<string, byte[]>(), []);
3335
newState.InitializeExistingState(currentState);
36+
var newStateValueProvider = new PersistentStateValueProvider(newState, serviceProvider);
3437

35-
Assert.True(newState.TryTake("test-key", customSerializer, out var retrievedValue));
38+
Assert.True(newStateValueProvider.TryTake("test-key", customSerializer, out var retrievedValue));
3639
Assert.Equal(testValue, retrievedValue);
3740
}
3841

@@ -47,10 +50,12 @@ public void TryTake_CanUseCustomSerializer()
4750
var state = new PersistentComponentState(new Dictionary<string, byte[]>(), []);
4851
state.InitializeExistingState(existingState);
4952

53+
var serviceProvider = new ServiceCollection().BuildServiceProvider();
54+
var stateValueProvider = new PersistentStateValueProvider(state, serviceProvider);
5055
var customSerializer = new TestStringSerializer();
5156

5257
// Act
53-
var success = state.TryTake("test-key", customSerializer, out var retrievedValue);
58+
var success = stateValueProvider.TryTake("test-key", customSerializer, out var retrievedValue);
5459

5560
// Assert
5661
Assert.True(success);

0 commit comments

Comments
 (0)