Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit a30e1e8

Browse files
committed
Add WCF-style Serialization Hook with JsConfig<T>.OnSerializeFn
1 parent 356c0ae commit a30e1e8

File tree

4 files changed

+228
-3
lines changed

4 files changed

+228
-3
lines changed

src/ServiceStack.Text/Common/JsWriter.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,18 +262,36 @@ public WriteObjectDelegate GetWriteFn<T>()
262262
return Serializer.WriteObjectString;
263263
}
264264

265+
WriteObjectDelegate ret = null;
266+
265267
var onSerializingFn = JsConfig<T>.OnSerializingFn;
266268
if (onSerializingFn != null)
267269
{
268-
return (w, x) => GetCoreWriteFn<T>()(w, onSerializingFn((T)x));
270+
ret = (w, x) => GetCoreWriteFn<T>()(w, onSerializingFn((T)x));
269271
}
270272

271273
if (JsConfig<T>.HasSerializeFn)
272274
{
273-
return JsConfig<T>.WriteFn<TSerializer>;
275+
ret = JsConfig<T>.WriteFn<TSerializer>;
276+
}
277+
278+
if (ret == null)
279+
{
280+
ret = GetCoreWriteFn<T>();
281+
}
282+
283+
var onSerializedFn = JsConfig<T>.OnSerializedFn;
284+
if (onSerializedFn != null)
285+
{
286+
var writerFunc = ret;
287+
ret = (w, x) =>
288+
{
289+
writerFunc(w, x);
290+
onSerializedFn((T)x);
291+
};
274292
}
275293

276-
return GetCoreWriteFn<T>();
294+
return ret;
277295
}
278296

279297
public void WriteValue(TextWriter writer, object value)

src/ServiceStack.Text/JsConfig.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,16 @@ public static Func<T, T> OnSerializingFn
778778
set { onSerializingFn = value; }
779779
}
780780

781+
/// <summary>
782+
/// Define custom after serialization hook
783+
/// </summary>
784+
private static Action<T> onSerializedFn;
785+
public static Action<T> OnSerializedFn
786+
{
787+
get { return onSerializedFn; }
788+
set { onSerializedFn = value; }
789+
}
790+
781791
/// <summary>
782792
/// Define custom deserialization fn for BCL Structs
783793
/// </summary>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
using System;
2+
using System.Linq;
3+
using System.Runtime.Serialization;
4+
using NUnit.Framework;
5+
6+
namespace ServiceStack.Text.Tests
7+
{
8+
[TestFixture]
9+
public class SerializationHookTests
10+
: TestBase
11+
{
12+
[TestFixtureSetUp]
13+
public void SetUp()
14+
{
15+
AddSerializeHooksForType<HookTestClass>();
16+
AddSerializeHooksForType<HookTestSubClass>();
17+
}
18+
19+
[Test]
20+
public void TypeSerializer_Serialize_hooks_on_base_class()
21+
{
22+
var original = new HookTestClass();
23+
var json = TypeSerializer.SerializeToString<HookTestClass>(original);
24+
25+
Assert.That(original.OnSerializedTouched, Is.True);
26+
Assert.That(original.OnSerializingTouched, Is.True);
27+
}
28+
29+
[Test]
30+
public void TypeSerializer_Serialize_hooks_on_sub_class()
31+
{
32+
var original = new HookTestSubClass();
33+
var json = TypeSerializer.SerializeToString<HookTestSubClass>(original);
34+
35+
Assert.That(original.OnSerializedTouched, Is.True);
36+
Assert.That(original.OnSerializingTouched, Is.True);
37+
}
38+
39+
[Test]
40+
public void TypeSerializer_Deserialize_hooks_on_base_class()
41+
{
42+
var original = new HookTestClass();
43+
44+
var json = TypeSerializer.SerializeToString<HookTestClass>(original);
45+
var deserialized = TypeSerializer.DeserializeFromString<HookTestClass>(json);
46+
47+
Assert.That(deserialized.OnDeserializedTouched, Is.True);
48+
}
49+
50+
[Test]
51+
public void TypeSerializer_Deserialize_hooks_on_sub_class()
52+
{
53+
var original = new HookTestSubClass();
54+
55+
var json = TypeSerializer.SerializeToString<HookTestSubClass>(original);
56+
var deserialized = TypeSerializer.DeserializeFromString<HookTestSubClass>(json);
57+
58+
Assert.That(deserialized.OnDeserializedTouched, Is.True);
59+
}
60+
61+
[Test]
62+
public void JsonSerializer_Serialize_hooks_on_base_class()
63+
{
64+
var original = new HookTestClass();
65+
var json = JsonSerializer.SerializeToString<HookTestClass>(original);
66+
67+
Assert.That(original.OnSerializedTouched, Is.True);
68+
Assert.That(original.OnSerializingTouched, Is.True);
69+
}
70+
71+
[Test]
72+
public void JsonSerializer_Serialize_hooks_on_sub_class()
73+
{
74+
var original = new HookTestSubClass();
75+
var json = JsonSerializer.SerializeToString<HookTestSubClass>(original);
76+
77+
Assert.That(original.OnSerializedTouched, Is.True);
78+
Assert.That(original.OnSerializingTouched, Is.True);
79+
}
80+
81+
[Test]
82+
public void JsonSerializer_Deserialize_hooks_on_base_class()
83+
{
84+
var original = new HookTestClass();
85+
86+
var json = JsonSerializer.SerializeToString<HookTestClass>(original);
87+
var deserialized = JsonSerializer.DeserializeFromString<HookTestClass>(json);
88+
89+
Assert.That(deserialized.OnDeserializedTouched, Is.True);
90+
}
91+
92+
[Test]
93+
public void JsonSerializer_Deserialize_hooks_on_sub_class()
94+
{
95+
var original = new HookTestSubClass();
96+
97+
var json = JsonSerializer.SerializeToString<HookTestSubClass>(original);
98+
var deserialized = JsonSerializer.DeserializeFromString<HookTestSubClass>(json);
99+
100+
Assert.That(deserialized.OnDeserializedTouched, Is.True);
101+
}
102+
103+
private void AddSerializeHooksForType<T>()
104+
{
105+
Type type = typeof(T);
106+
System.Reflection.MethodInfo[] typeMethods = type.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
107+
var onSerializingMethods = typeMethods.Where(m => m.GetCustomAttributes(typeof(OnSerializingAttribute), true).Length > 0);
108+
var OnDeserializedMethods = typeMethods.Where(m => m.GetCustomAttributes(typeof(OnDeserializedAttribute), true).Length > 0);
109+
var OnSerializedMethods = typeMethods.Where(m => m.GetCustomAttributes(typeof(OnSerializedAttribute), true).Length > 0);
110+
Object[] Parameters = { null };
111+
112+
if (onSerializingMethods.Any())
113+
{
114+
ServiceStack.Text.JsConfig<T>.OnSerializingFn = s =>
115+
{
116+
foreach (var method in onSerializingMethods)
117+
method.Invoke(s, Parameters);
118+
119+
return s;
120+
};
121+
}
122+
123+
if (OnSerializedMethods.Any())
124+
{
125+
ServiceStack.Text.JsConfig<T>.OnSerializedFn = s =>
126+
{
127+
foreach (var method in OnSerializedMethods)
128+
method.Invoke(s, Parameters);
129+
};
130+
}
131+
132+
if (OnDeserializedMethods.Any())
133+
{
134+
ServiceStack.Text.JsConfig<T>.OnDeserializedFn = s =>
135+
{
136+
foreach (var method in OnDeserializedMethods)
137+
method.Invoke(s, Parameters);
138+
139+
return s;
140+
};
141+
}
142+
}
143+
144+
class HookTestClass
145+
{
146+
public bool OnDeserializingTouched { get; set; }
147+
public bool OnDeserializedTouched { get; set; }
148+
public bool OnSerializingTouched { get; set; }
149+
public bool OnSerializedTouched { get; set; }
150+
151+
/// <summary>
152+
/// Will be executed when deserializing starts
153+
/// </summary>
154+
/// <param name="ctx"></param>
155+
[OnDeserializing]
156+
protected void OnDeserializing(StreamingContext ctx)
157+
{
158+
OnDeserializingTouched = true;
159+
}
160+
161+
/// <summary>
162+
/// Will be executed when deserializing finished
163+
/// </summary>
164+
/// <param name="ctx"></param>
165+
[OnDeserialized]
166+
protected void OnDeserialized(StreamingContext ctx)
167+
{
168+
OnDeserializedTouched = true;
169+
}
170+
171+
/// <summary>
172+
/// Will be executed when serializing starts
173+
/// </summary>
174+
/// <param name="ctx"></param>
175+
[OnSerializing]
176+
protected void OnSerializing(StreamingContext ctx)
177+
{
178+
OnSerializingTouched = true;
179+
}
180+
181+
/// <summary>
182+
/// Will be executed when serializing finished
183+
/// </summary>
184+
/// <param name="ctx"></param>
185+
[OnSerialized]
186+
protected void OnSerialized(StreamingContext ctx)
187+
{
188+
OnSerializedTouched = true;
189+
}
190+
}
191+
192+
class HookTestSubClass : HookTestClass
193+
{
194+
}
195+
}
196+
}

tests/ServiceStack.Text.Tests/ServiceStack.Text.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
</Reference>
177177
</ItemGroup>
178178
<ItemGroup>
179+
<Compile Include="SerializationHookTests.cs" />
179180
<Compile Include="StaticAccessorTests.cs" />
180181
<Compile Include="AdhocModelTests.cs" />
181182
<Compile Include="AnonymousTypes.cs" />

0 commit comments

Comments
 (0)