Skip to content

Commit b4ec5b0

Browse files
committed
Fixing Node.js nested object serialization issue (#3)
1 parent e9dc9a5 commit b4ec5b0

File tree

4 files changed

+160
-3
lines changed

4 files changed

+160
-3
lines changed

sample/QueueTrigger/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var util = require('util');
22

33
module.exports = function (context) {
4-
context.log('Node.js queue trigger function processed work item ' + util.inspect(context.workItem.id));
4+
context.log('Node.js queue trigger function processed work item ' + context.workItem.id);
55

66
context.output({
77
receipt: JSON.stringify(context.workItem)

src/WebJobs.Script/Description/NodeFunctionInvoker.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,10 @@ private Dictionary<string, object> CreateContext(object input, TraceWriter trace
118118
Type triggerParameterType = input.GetType();
119119
if (triggerParameterType == typeof(string))
120120
{
121-
// convert string into Dictionary which Edge will convert into an object
121+
// convert string into Dictionary (recursively) which Edge will convert into an object
122122
// before invoking the function
123-
input = JsonConvert.DeserializeObject<Dictionary<string, object>>((string)input);
123+
input = JsonConvert.DeserializeObject<Dictionary<string, object>>(
124+
(string)input, new DictionaryJsonConverter());
124125
}
125126

126127
// create a TraceWriter wrapper that can be exposed to Node.js
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Newtonsoft.Json;
7+
using Newtonsoft.Json.Linq;
8+
9+
namespace Microsoft.Azure.WebJobs.Script
10+
{
11+
12+
public class DictionaryJsonConverter : JsonConverter
13+
{
14+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
15+
{
16+
WriteValue(writer, value);
17+
}
18+
19+
private void WriteValue(JsonWriter writer, object value)
20+
{
21+
var token = JToken.FromObject(value);
22+
switch (token.Type)
23+
{
24+
case JTokenType.Object:
25+
WriteObject(writer, value);
26+
break;
27+
case JTokenType.Array:
28+
WriteArray(writer, value);
29+
break;
30+
default:
31+
writer.WriteValue(value);
32+
break;
33+
}
34+
}
35+
36+
private void WriteObject(JsonWriter writer, object value)
37+
{
38+
writer.WriteStartObject();
39+
40+
var obj = value as IDictionary<string, object>;
41+
foreach (var kvp in obj)
42+
{
43+
writer.WritePropertyName(kvp.Key);
44+
WriteValue(writer, kvp.Value);
45+
}
46+
47+
writer.WriteEndObject();
48+
}
49+
50+
private void WriteArray(JsonWriter writer, object value)
51+
{
52+
writer.WriteStartArray();
53+
54+
var array = value as IEnumerable<object>;
55+
foreach (var o in array)
56+
{
57+
WriteValue(writer, o);
58+
}
59+
60+
writer.WriteEndArray();
61+
}
62+
63+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
64+
{
65+
return ReadValue(reader);
66+
}
67+
68+
private object ReadValue(JsonReader reader)
69+
{
70+
while (reader.TokenType == JsonToken.Comment)
71+
{
72+
if (!reader.Read())
73+
{
74+
throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
75+
}
76+
}
77+
78+
switch (reader.TokenType)
79+
{
80+
case JsonToken.StartObject:
81+
return ReadObject(reader);
82+
case JsonToken.StartArray:
83+
return ReadArray(reader);
84+
case JsonToken.Integer:
85+
case JsonToken.Float:
86+
case JsonToken.String:
87+
case JsonToken.Boolean:
88+
case JsonToken.Undefined:
89+
case JsonToken.Null:
90+
case JsonToken.Date:
91+
case JsonToken.Bytes:
92+
return reader.Value;
93+
default:
94+
string msg = string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType);
95+
throw new JsonSerializationException(msg);
96+
}
97+
}
98+
99+
private object ReadArray(JsonReader reader)
100+
{
101+
IList<object> list = new List<object>();
102+
103+
while (reader.Read())
104+
{
105+
switch (reader.TokenType)
106+
{
107+
case JsonToken.Comment:
108+
break;
109+
default:
110+
var value = ReadValue(reader);
111+
list.Add(value);
112+
break;
113+
case JsonToken.EndArray:
114+
return list;
115+
}
116+
}
117+
118+
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
119+
}
120+
121+
private object ReadObject(JsonReader reader)
122+
{
123+
var obj = new Dictionary<string, object>();
124+
125+
while (reader.Read())
126+
{
127+
switch (reader.TokenType)
128+
{
129+
case JsonToken.PropertyName:
130+
var propertyName = reader.Value.ToString();
131+
132+
if (!reader.Read())
133+
{
134+
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
135+
}
136+
137+
var value = ReadValue(reader);
138+
obj[propertyName] = value;
139+
break;
140+
case JsonToken.Comment:
141+
break;
142+
case JsonToken.EndObject:
143+
return obj;
144+
}
145+
}
146+
147+
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
148+
}
149+
150+
public override bool CanConvert(Type objectType)
151+
{
152+
return typeof(IDictionary<string, object>).IsAssignableFrom(objectType);
153+
}
154+
}
155+
}

src/WebJobs.Script/WebJobs.Script.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
<Compile Include="Description\ScriptFunctionInvoker.cs" />
180180
<Compile Include="Description\NodeFunctionDescriptorProvider.cs" />
181181
<Compile Include="Description\NodeFunctionInvoker.cs" />
182+
<Compile Include="DictionaryJsonConverter.cs" />
182183
<Compile Include="Properties\AssemblyInfo.cs" />
183184
<Compile Include="Config\ScriptHostConfiguration.cs" />
184185
<Compile Include="Config\TypeLocator.cs" />

0 commit comments

Comments
 (0)