Skip to content

Commit 2329100

Browse files
authored
Verify type is expected when serializing (#190)
1 parent 2600ec4 commit 2329100

File tree

2 files changed

+210
-10
lines changed

2 files changed

+210
-10
lines changed

src/Services/SessionState/Serialization/JsonSessionKeySerializer.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,38 @@
33

44
using System;
55
using System.Text.Json;
6+
using Microsoft.Extensions.Logging;
67
using Microsoft.Extensions.Options;
78

89
namespace Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization;
910

10-
internal class JsonSessionKeySerializer : ISessionKeySerializer
11+
internal partial class JsonSessionKeySerializer : ISessionKeySerializer
1112
{
12-
private readonly JsonSessionSerializerOptions _options;
13+
private readonly IOptions<JsonSessionSerializerOptions> _options;
14+
private readonly ILogger<JsonSessionKeySerializer> _logger;
1315

14-
public JsonSessionKeySerializer(IOptions<JsonSessionSerializerOptions> options)
16+
public JsonSessionKeySerializer(IOptions<JsonSessionSerializerOptions> options, ILogger<JsonSessionKeySerializer> logger)
1517
{
16-
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
18+
_options = options ?? throw new ArgumentNullException(nameof(options));
19+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
1720
}
1821

22+
[LoggerMessage(0, LogLevel.Error, "Unexpected JSON serialize/deserialization error for '{Key}' expected type '{Type}'")]
23+
private partial void LogException(Exception e, string key, string type);
24+
1925
public bool TryDeserialize(string key, byte[] bytes, out object? obj)
2026
{
21-
if (_options.KnownKeys.TryGetValue(key, out var type))
27+
if (_options.Value.KnownKeys.TryGetValue(key, out var type))
2228
{
23-
obj = JsonSerializer.Deserialize(bytes, type);
24-
return true;
29+
try
30+
{
31+
obj = JsonSerializer.Deserialize(bytes, type);
32+
return true;
33+
}
34+
catch (JsonException e)
35+
{
36+
LogException(e, key, type.Name);
37+
}
2538
}
2639

2740
obj = default;
@@ -30,10 +43,17 @@ public bool TryDeserialize(string key, byte[] bytes, out object? obj)
3043

3144
public bool TrySerialize(string key, object value, out byte[] bytes)
3245
{
33-
if (_options.KnownKeys.TryGetValue(key, out var type))
46+
if (_options.Value.KnownKeys.TryGetValue(key, out var type) && type == value.GetType())
3447
{
35-
bytes = JsonSerializer.SerializeToUtf8Bytes(value, type);
36-
return true;
48+
try
49+
{
50+
bytes = JsonSerializer.SerializeToUtf8Bytes(value, type);
51+
return true;
52+
}
53+
catch (JsonException e)
54+
{
55+
LogException(e, key, type.Name);
56+
}
3757
}
3858

3959
bytes = Array.Empty<byte>();
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Linq;
5+
using Autofac.Extras.Moq;
6+
using AutoFixture;
7+
using Microsoft.Extensions.Options;
8+
using Xunit;
9+
10+
namespace Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.Tests;
11+
12+
public class JsonSessionKeySerializerTests
13+
{
14+
private readonly Fixture _fixture;
15+
16+
public JsonSessionKeySerializerTests()
17+
{
18+
_fixture = new Fixture();
19+
}
20+
21+
[Fact]
22+
public void SerializeNothingRegistered()
23+
{
24+
// Arrange
25+
using var mock = AutoMock.GetLoose();
26+
var key = _fixture.Create<string>();
27+
28+
var options = new JsonSessionSerializerOptions();
29+
mock.Mock<IOptions<JsonSessionSerializerOptions>>().Setup(o => o.Value).Returns(options);
30+
31+
var serializer = mock.Create<JsonSessionKeySerializer>();
32+
33+
// Act
34+
var result = serializer.TrySerialize(key, new Type1(), out var bytes);
35+
36+
// Assert
37+
Assert.False(result);
38+
Assert.Empty(bytes);
39+
}
40+
41+
[Fact]
42+
public void DeserializeNothingRegistered()
43+
{
44+
// Arrange
45+
using var mock = AutoMock.GetLoose();
46+
var key = _fixture.Create<string>();
47+
var value = _fixture.CreateMany<byte>().ToArray();
48+
49+
var options = new JsonSessionSerializerOptions();
50+
mock.Mock<IOptions<JsonSessionSerializerOptions>>().Setup(o => o.Value).Returns(options);
51+
52+
var serializer = mock.Create<JsonSessionKeySerializer>();
53+
54+
// Act
55+
var result = serializer.TryDeserialize(key, value, out var obj);
56+
57+
// Assert
58+
Assert.False(result);
59+
Assert.Null(obj);
60+
}
61+
62+
[Fact]
63+
public void SerializeTypeRegistered()
64+
{
65+
// Arrange
66+
using var mock = AutoMock.GetLoose();
67+
var key = _fixture.Create<string>();
68+
var value = _fixture.CreateMany<byte>().ToArray();
69+
70+
var options = new JsonSessionSerializerOptions
71+
{
72+
KnownKeys =
73+
{
74+
{ key, typeof(Type1) },
75+
}
76+
};
77+
mock.Mock<IOptions<JsonSessionSerializerOptions>>().Setup(o => o.Value).Returns(options);
78+
79+
var serializer = mock.Create<JsonSessionKeySerializer>();
80+
81+
// Act
82+
var result = serializer.TrySerialize(key, new Type1(), out var bytes);
83+
84+
// Assert
85+
Assert.True(result);
86+
Assert.Equal(new byte[] { 123, 125 }, bytes);
87+
}
88+
89+
[Fact]
90+
public void SerializeDerivedTypeRegistered()
91+
{
92+
// Arrange
93+
using var mock = AutoMock.GetLoose();
94+
var key = _fixture.Create<string>();
95+
var value = _fixture.CreateMany<byte>().ToArray();
96+
97+
var options = new JsonSessionSerializerOptions
98+
{
99+
KnownKeys =
100+
{
101+
{ key, typeof(Type2) },
102+
}
103+
};
104+
mock.Mock<IOptions<JsonSessionSerializerOptions>>().Setup(o => o.Value).Returns(options);
105+
106+
var serializer = mock.Create<JsonSessionKeySerializer>();
107+
108+
// Act
109+
var result = serializer.TrySerialize(key, new Type2Derived(), out var bytes);
110+
111+
// Assert
112+
Assert.False(result);
113+
Assert.Empty(bytes);
114+
}
115+
116+
[Fact]
117+
public void DeserializeTypeRegistered()
118+
{
119+
// Arrange
120+
using var mock = AutoMock.GetLoose();
121+
var key = _fixture.Create<string>();
122+
var value = new byte[] { 123, 125 };
123+
124+
var options = new JsonSessionSerializerOptions
125+
{
126+
KnownKeys =
127+
{
128+
{ key, typeof(Type1) },
129+
}
130+
};
131+
mock.Mock<IOptions<JsonSessionSerializerOptions>>().Setup(o => o.Value).Returns(options);
132+
133+
var serializer = mock.Create<JsonSessionKeySerializer>();
134+
135+
// Act
136+
var result = serializer.TryDeserialize(key, value, out var obj);
137+
138+
// Assert
139+
Assert.True(result);
140+
Assert.NotNull(obj);
141+
}
142+
143+
[Fact]
144+
public void SerializeIncorrectTypeRegistered()
145+
{
146+
// Arrange
147+
using var mock = AutoMock.GetLoose();
148+
var key = _fixture.Create<string>();
149+
150+
var options = new JsonSessionSerializerOptions
151+
{
152+
KnownKeys =
153+
{
154+
{ key, typeof(Type1) },
155+
}
156+
};
157+
mock.Mock<IOptions<JsonSessionSerializerOptions>>().Setup(o => o.Value).Returns(options);
158+
159+
var serializer = mock.Create<JsonSessionKeySerializer>();
160+
161+
// Act
162+
var result = serializer.TrySerialize(key, new Type2(), out var bytes);
163+
164+
// Assert
165+
Assert.False(result);
166+
Assert.Empty(bytes);
167+
}
168+
169+
private class Type1
170+
{
171+
}
172+
173+
private class Type2
174+
{
175+
}
176+
177+
private class Type2Derived : Type2
178+
{
179+
}
180+
}

0 commit comments

Comments
 (0)