Skip to content

Commit d8b5f8c

Browse files
committed
tmp
1 parent 7b556dd commit d8b5f8c

File tree

2 files changed

+60
-27
lines changed

2 files changed

+60
-27
lines changed

src/Shared/Components/PrerenderComponentApplicationStore.cs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Buffers;
66
using System.Collections.Generic;
7+
using System.IO.Pipelines;
78
using System.Text.Json;
89
using System.Threading.Tasks;
910
using Microsoft.AspNetCore.Components.Lifetime;
@@ -24,7 +25,12 @@ public PrerenderComponentApplicationStore(string existingState)
2425
throw new ArgumentNullException(nameof(existingState));
2526
}
2627

27-
var state = JsonSerializer.Deserialize<Dictionary<string, byte[]>>(Convert.FromBase64String(existingState));
28+
DeserializeState(Convert.FromBase64String(existingState));
29+
}
30+
31+
protected void DeserializeState(byte[] existingState)
32+
{
33+
var state = JsonSerializer.Deserialize<Dictionary<string, byte[]>>(existingState);
2834
if (state == null)
2935
{
3036
throw new ArgumentException("Could not deserialize state correctly", nameof(existingState));
@@ -50,48 +56,74 @@ public Task<IDictionary<string, ReadOnlySequence<byte>>> GetPersistedStateAsync(
5056
return Task.FromResult((IDictionary<string, ReadOnlySequence<byte>>)ExistingState);
5157
}
5258

53-
protected virtual byte[] SerializeState(IReadOnlyDictionary<string, ReadOnlySequence<byte>> state)
59+
protected virtual async Task<byte[]> SerializeState(IReadOnlyDictionary<string, ReadOnlySequence<byte>> state)
5460
{
5561
// System.Text.Json doesn't support serializing ReadonlySequence<byte> so we need to buffer
5662
// the data with a memory pool here. We will change our serialization strategy in the future here
5763
// so that we can avoid this step.
58-
var pool = MemoryPool<byte>.Shared;
59-
var memory = new List<IMemoryOwner<byte>>();
60-
var serialization = new Dictionary<string, Memory<byte>>();
61-
try
64+
var pipe = new Pipe();
65+
var pipeWriter = pipe.Writer;
66+
var jsonWriter = new Utf8JsonWriter(pipeWriter);
67+
jsonWriter.WriteStartObject();
68+
foreach (var (key, value) in state)
69+
{
70+
if (value.IsSingleSegment)
71+
{
72+
jsonWriter.WriteBase64String(key, value.First.Span);
73+
}
74+
else
75+
{
76+
WriteMultipleSegments(jsonWriter, key, value);
77+
}
78+
jsonWriter.Flush();
79+
}
80+
81+
jsonWriter.WriteEndObject();
82+
jsonWriter.Flush();
83+
pipe.Writer.Complete();
84+
var result = await ReadToEnd(pipe.Reader);
85+
return result.ToArray();
86+
87+
async Task<ReadOnlySequence<byte>> ReadToEnd(PipeReader reader)
6288
{
63-
foreach (var (key, value) in state)
89+
var result = await reader.ReadAsync();
90+
reader.AdvanceTo(result.Buffer.Start, result.Buffer.End);
91+
while (!result.IsCompleted)
6492
{
65-
IMemoryOwner<byte> buffer = null;
66-
if (value.Length < pool.MaxBufferSize)
67-
{
68-
buffer = pool.Rent((int)value.Length);
69-
memory.Add(buffer);
70-
value.CopyTo(buffer.Memory.Span.Slice(0, (int)value.Length));
71-
}
72-
73-
serialization.Add(key, buffer != null ? buffer.Memory.Slice(0, (int)value.Length) : value.ToArray());
93+
// Consume nothing, just wait for everything
94+
result = await reader.ReadAsync();
95+
reader.AdvanceTo(result.Buffer.Start, result.Buffer.End);
7496
}
7597

76-
return JsonSerializer.SerializeToUtf8Bytes(serialization, JsonSerializerOptionsProvider.Options);
98+
return result.Buffer;
7799
}
78-
finally
100+
101+
static void WriteMultipleSegments(Utf8JsonWriter jsonWriter, string key, ReadOnlySequence<byte> value)
79102
{
80-
serialization.Clear();
81-
foreach (var item in memory)
103+
byte[] unescapedArray = null;
104+
var valueLenght = (int)value.Length;
105+
106+
Span<byte> valueSegment = value.Length <= 256 ?
107+
stackalloc byte[valueLenght] :
108+
(unescapedArray = ArrayPool<byte>.Shared.Rent(valueLenght)).AsSpan().Slice(0, valueLenght);
109+
110+
value.CopyTo(valueSegment);
111+
jsonWriter.WriteBase64String(key, valueSegment);
112+
113+
if (unescapedArray != null)
82114
{
83-
item.Dispose();
115+
valueSegment.Clear();
116+
ArrayPool<byte>.Shared.Return(unescapedArray);
84117
}
85118
}
86119
}
87120

88-
public Task PersistStateAsync(IReadOnlyDictionary<string, ReadOnlySequence<byte>> state)
121+
public async Task PersistStateAsync(IReadOnlyDictionary<string, ReadOnlySequence<byte>> state)
89122
{
90-
var bytes = SerializeState(state);
123+
var bytes = await SerializeState(state);
91124

92125
var result = Convert.ToBase64String(bytes);
93126
PersistedState = result;
94-
return Task.CompletedTask;
95127
}
96128
}
97129
}

src/Shared/Components/ProtectedPrerenderComponentApplicationStore.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Buffers;
66
using System.Collections.Generic;
77
using System.Text.Json;
8+
using System.Threading.Tasks;
89
using Microsoft.AspNetCore.DataProtection;
910

1011
namespace Microsoft.AspNetCore.Components
@@ -21,12 +22,12 @@ public ProtectedPrerenderComponentApplicationStore(IDataProtectionProvider dataP
2122
public ProtectedPrerenderComponentApplicationStore(string existingState, IDataProtectionProvider dataProtectionProvider)
2223
{
2324
CreateProtector(dataProtectionProvider);
24-
ExistingState = JsonSerializer.Deserialize<Dictionary<string, ReadOnlySequence<byte>>>(_protector.Unprotect(Convert.FromBase64String(existingState)));
25+
DeserializeState(_protector.Unprotect(Convert.FromBase64String(existingState)));
2526
}
2627

27-
protected override byte[] SerializeState(IReadOnlyDictionary<string, ReadOnlySequence<byte>> state)
28+
protected async override Task<byte[]> SerializeState(IReadOnlyDictionary<string, ReadOnlySequence<byte>> state)
2829
{
29-
var bytes = base.SerializeState(state);
30+
var bytes = await base.SerializeState(state);
3031
if (_protector != null)
3132
{
3233
bytes = _protector.Protect(bytes);

0 commit comments

Comments
 (0)