Chaining JSON transformations with visitors
up vote
3
down vote
favorite
I have currently two use-cases that require JSON transformations before it can be deserialized.
- The first use-case requires changing the custom short type property name from
$t
to$type
and resolving full type names from their aliases. This is the same as in my previous question. - The second use-case is about fixing property names that contain whitespaces and need to be trimmed like
> Name <
instead of>Name<
(yeah, I've spent quite some time spotting this mistake in a large file recently).
My previous solution supported only resolving type names and was build with a custom JsonTextReader
. Now that I wanted to add another trasnformation to it, I noticed that it cannot be chained because the reader supports forward-only reading and there is no way to add to it.
I've changed my strategy and used the JToken.Parse
instead with a couple of visitors that work similar to the ExpressionVisitor
.
The first one of them is the JsonVisitor
that recursively rebuilds the tree and allows to intercept this process by overriding VisitProperty
:
public delegate JToken VisitJsonCallback(JToken token);
public class JsonVisitor
{
public static JToken Visit(JToken token, params JsonVisitor visitors)
{
return visitors.Aggregate(token, (current, visitor) => visitor.Visit(current));
}
public static VisitJsonCallback Create(params JsonVisitor visitors) => jToken => Visit(jToken, visitors);
public JToken Visit(JToken token)
{
return
token is JValue
? token
: VisitInternal(token, CreateJContainer(token.Type));
}
private JToken VisitInternal(JToken token, JContainer result)
{
if (token is JValue)
{
return token;
}
foreach (var element in token)
{
switch (element)
{
case JProperty property:
var visitedProperty = VisitProperty(property);
result.Add(visitedProperty);
break;
default:
result.Add(Visit(element));
break;
}
}
return result;
}
protected virtual JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name, Visit(property.Value));
}
private static JContainer CreateJContainer(JTokenType tokenType)
{
switch (tokenType)
{
case JTokenType.Object: return new JObject();
case JTokenType.Array: return new JArray();
default: throw new ArgumentOutOfRangeException($"Invalid type: {tokenType}");
}
}
}
Since I didn't have any other use cases yet, it's the only overridable API right now but I think it should be easy to extend it in future.
Then I have two more of them that cover both use-cases (here in the reverse order)
public class PropertyNameTrimmer : JsonVisitor
{
protected override JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name.Trim(), Visit(property.Value));
}
}
public class TypeResolver : JsonVisitor
{
private readonly string _typePropertyName;
private readonly Func<string, string> _resolveType;
public TypeResolver(string typePropertyName, Func<string, string> resolveType)
{
_typePropertyName = typePropertyName;
_resolveType = resolveType;
}
protected override JProperty VisitProperty(JProperty property)
{
return
property.Name == _typePropertyName
? new JProperty("$type", _resolveType(property.Value.Value<string>()))
: base.VisitProperty(property);
}
}
Example
I would use them by passing the result from one to the other:
void Main()
{
var json = @"{ ""$t"": ""MyType"", ""User "": ""John"", ""Nested"": { ""$t"": ""OtherType"", "" ZIP"": 12345 }, ""Numbers"": [1, 2, 3 ] }";
var jToken = JToken.Parse(json);
jToken.ToString().Dump("Original");
var propertyNameTrimmer = new PropertyNameTrimmer();
var typeResolver = new TypeResolver("$t", shortName => shortName + "_resolved");
var trimmed = propertyNameTrimmer.Visit(jToken);
trimmed.ToString().Dump(nameof(PropertyNameTrimmer));
var typeResolved = typeResolver.Visit(trimmed);
typeResolved.ToString().Dump(nameof(TypeResolver));
}
So calling them in this order produces:
Original
{
"$t": "MyType",
"User ": "John",
"Nested": {
"$t": "OtherType",
" ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
PropertyNameTrimmer - whitespaces removed from property names
{
"$t": "MyType",
"User": "John",
"Nested": {
"$t": "OtherType",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
TypeResolver - property names changed and types resolved
{
"$type": "MyType_resolved",
"User": "John",
"Nested": {
"$type": "OtherType_resolved",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
How do you like this solution? Have I missed anything important (but null-checks) and can I improve this in any way?
c# json json.net visitor-pattern
|
show 1 more comment
up vote
3
down vote
favorite
I have currently two use-cases that require JSON transformations before it can be deserialized.
- The first use-case requires changing the custom short type property name from
$t
to$type
and resolving full type names from their aliases. This is the same as in my previous question. - The second use-case is about fixing property names that contain whitespaces and need to be trimmed like
> Name <
instead of>Name<
(yeah, I've spent quite some time spotting this mistake in a large file recently).
My previous solution supported only resolving type names and was build with a custom JsonTextReader
. Now that I wanted to add another trasnformation to it, I noticed that it cannot be chained because the reader supports forward-only reading and there is no way to add to it.
I've changed my strategy and used the JToken.Parse
instead with a couple of visitors that work similar to the ExpressionVisitor
.
The first one of them is the JsonVisitor
that recursively rebuilds the tree and allows to intercept this process by overriding VisitProperty
:
public delegate JToken VisitJsonCallback(JToken token);
public class JsonVisitor
{
public static JToken Visit(JToken token, params JsonVisitor visitors)
{
return visitors.Aggregate(token, (current, visitor) => visitor.Visit(current));
}
public static VisitJsonCallback Create(params JsonVisitor visitors) => jToken => Visit(jToken, visitors);
public JToken Visit(JToken token)
{
return
token is JValue
? token
: VisitInternal(token, CreateJContainer(token.Type));
}
private JToken VisitInternal(JToken token, JContainer result)
{
if (token is JValue)
{
return token;
}
foreach (var element in token)
{
switch (element)
{
case JProperty property:
var visitedProperty = VisitProperty(property);
result.Add(visitedProperty);
break;
default:
result.Add(Visit(element));
break;
}
}
return result;
}
protected virtual JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name, Visit(property.Value));
}
private static JContainer CreateJContainer(JTokenType tokenType)
{
switch (tokenType)
{
case JTokenType.Object: return new JObject();
case JTokenType.Array: return new JArray();
default: throw new ArgumentOutOfRangeException($"Invalid type: {tokenType}");
}
}
}
Since I didn't have any other use cases yet, it's the only overridable API right now but I think it should be easy to extend it in future.
Then I have two more of them that cover both use-cases (here in the reverse order)
public class PropertyNameTrimmer : JsonVisitor
{
protected override JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name.Trim(), Visit(property.Value));
}
}
public class TypeResolver : JsonVisitor
{
private readonly string _typePropertyName;
private readonly Func<string, string> _resolveType;
public TypeResolver(string typePropertyName, Func<string, string> resolveType)
{
_typePropertyName = typePropertyName;
_resolveType = resolveType;
}
protected override JProperty VisitProperty(JProperty property)
{
return
property.Name == _typePropertyName
? new JProperty("$type", _resolveType(property.Value.Value<string>()))
: base.VisitProperty(property);
}
}
Example
I would use them by passing the result from one to the other:
void Main()
{
var json = @"{ ""$t"": ""MyType"", ""User "": ""John"", ""Nested"": { ""$t"": ""OtherType"", "" ZIP"": 12345 }, ""Numbers"": [1, 2, 3 ] }";
var jToken = JToken.Parse(json);
jToken.ToString().Dump("Original");
var propertyNameTrimmer = new PropertyNameTrimmer();
var typeResolver = new TypeResolver("$t", shortName => shortName + "_resolved");
var trimmed = propertyNameTrimmer.Visit(jToken);
trimmed.ToString().Dump(nameof(PropertyNameTrimmer));
var typeResolved = typeResolver.Visit(trimmed);
typeResolved.ToString().Dump(nameof(TypeResolver));
}
So calling them in this order produces:
Original
{
"$t": "MyType",
"User ": "John",
"Nested": {
"$t": "OtherType",
" ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
PropertyNameTrimmer - whitespaces removed from property names
{
"$t": "MyType",
"User": "John",
"Nested": {
"$t": "OtherType",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
TypeResolver - property names changed and types resolved
{
"$type": "MyType_resolved",
"User": "John",
"Nested": {
"$type": "OtherType_resolved",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
How do you like this solution? Have I missed anything important (but null-checks) and can I improve this in any way?
c# json json.net visitor-pattern
Your visitor looks fine for what it does, but why rewrite property names instead of throwing an exception:"Unknown property: 'User ' at position ..."
? That also catches other problems like typos ("Usr"
) and case differences ("Zip"
), which are difficult to auto-correct due to ambiguity.
– Pieter Witvoet
yesterday
@PieterWitvoet yeah, it's a tough decision and I actually wasn't sure (and I'm still not) which one would be better, fixing or throwing exceptions. I was also going to allow dashes in property names that I would rewrite toC#
valid names. Typos are difficult to handle anyway because if a property is optional it's hard to say whether it's something else or a typo. I guess I cannot eliminate all mistakes but at least reduce the probability. Btw, json is case-insensitive.
– t3chb0t
yesterday
@PieterWitvoet for a complete validation I'll probably should use json-schema but I'm not sure about its license and whether I could use it at work... most likely not so I'm not even trying but even when using json-schema I still need to rewrite some parts of it ;-)
– t3chb0t
yesterday
JSON isn't case-insensitive, but I see what you mean - Json.NET will try to find an exact match, but falls back to a case-insensitive check. Either way, it looks like passing aJsonSerializerSettings
instance withMissingMemberHandling
set toError
should do the trick.
– Pieter Witvoet
yesterday
@PieterWitvoet ok, it looks like you're correct with the case sensitivity, however, I'm glad nobody takes this rule serious, it'd break the entire internet if it suddenly would be respected - I find this rule is pretty stupid ;-]
– t3chb0t
yesterday
|
show 1 more comment
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I have currently two use-cases that require JSON transformations before it can be deserialized.
- The first use-case requires changing the custom short type property name from
$t
to$type
and resolving full type names from their aliases. This is the same as in my previous question. - The second use-case is about fixing property names that contain whitespaces and need to be trimmed like
> Name <
instead of>Name<
(yeah, I've spent quite some time spotting this mistake in a large file recently).
My previous solution supported only resolving type names and was build with a custom JsonTextReader
. Now that I wanted to add another trasnformation to it, I noticed that it cannot be chained because the reader supports forward-only reading and there is no way to add to it.
I've changed my strategy and used the JToken.Parse
instead with a couple of visitors that work similar to the ExpressionVisitor
.
The first one of them is the JsonVisitor
that recursively rebuilds the tree and allows to intercept this process by overriding VisitProperty
:
public delegate JToken VisitJsonCallback(JToken token);
public class JsonVisitor
{
public static JToken Visit(JToken token, params JsonVisitor visitors)
{
return visitors.Aggregate(token, (current, visitor) => visitor.Visit(current));
}
public static VisitJsonCallback Create(params JsonVisitor visitors) => jToken => Visit(jToken, visitors);
public JToken Visit(JToken token)
{
return
token is JValue
? token
: VisitInternal(token, CreateJContainer(token.Type));
}
private JToken VisitInternal(JToken token, JContainer result)
{
if (token is JValue)
{
return token;
}
foreach (var element in token)
{
switch (element)
{
case JProperty property:
var visitedProperty = VisitProperty(property);
result.Add(visitedProperty);
break;
default:
result.Add(Visit(element));
break;
}
}
return result;
}
protected virtual JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name, Visit(property.Value));
}
private static JContainer CreateJContainer(JTokenType tokenType)
{
switch (tokenType)
{
case JTokenType.Object: return new JObject();
case JTokenType.Array: return new JArray();
default: throw new ArgumentOutOfRangeException($"Invalid type: {tokenType}");
}
}
}
Since I didn't have any other use cases yet, it's the only overridable API right now but I think it should be easy to extend it in future.
Then I have two more of them that cover both use-cases (here in the reverse order)
public class PropertyNameTrimmer : JsonVisitor
{
protected override JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name.Trim(), Visit(property.Value));
}
}
public class TypeResolver : JsonVisitor
{
private readonly string _typePropertyName;
private readonly Func<string, string> _resolveType;
public TypeResolver(string typePropertyName, Func<string, string> resolveType)
{
_typePropertyName = typePropertyName;
_resolveType = resolveType;
}
protected override JProperty VisitProperty(JProperty property)
{
return
property.Name == _typePropertyName
? new JProperty("$type", _resolveType(property.Value.Value<string>()))
: base.VisitProperty(property);
}
}
Example
I would use them by passing the result from one to the other:
void Main()
{
var json = @"{ ""$t"": ""MyType"", ""User "": ""John"", ""Nested"": { ""$t"": ""OtherType"", "" ZIP"": 12345 }, ""Numbers"": [1, 2, 3 ] }";
var jToken = JToken.Parse(json);
jToken.ToString().Dump("Original");
var propertyNameTrimmer = new PropertyNameTrimmer();
var typeResolver = new TypeResolver("$t", shortName => shortName + "_resolved");
var trimmed = propertyNameTrimmer.Visit(jToken);
trimmed.ToString().Dump(nameof(PropertyNameTrimmer));
var typeResolved = typeResolver.Visit(trimmed);
typeResolved.ToString().Dump(nameof(TypeResolver));
}
So calling them in this order produces:
Original
{
"$t": "MyType",
"User ": "John",
"Nested": {
"$t": "OtherType",
" ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
PropertyNameTrimmer - whitespaces removed from property names
{
"$t": "MyType",
"User": "John",
"Nested": {
"$t": "OtherType",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
TypeResolver - property names changed and types resolved
{
"$type": "MyType_resolved",
"User": "John",
"Nested": {
"$type": "OtherType_resolved",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
How do you like this solution? Have I missed anything important (but null-checks) and can I improve this in any way?
c# json json.net visitor-pattern
I have currently two use-cases that require JSON transformations before it can be deserialized.
- The first use-case requires changing the custom short type property name from
$t
to$type
and resolving full type names from their aliases. This is the same as in my previous question. - The second use-case is about fixing property names that contain whitespaces and need to be trimmed like
> Name <
instead of>Name<
(yeah, I've spent quite some time spotting this mistake in a large file recently).
My previous solution supported only resolving type names and was build with a custom JsonTextReader
. Now that I wanted to add another trasnformation to it, I noticed that it cannot be chained because the reader supports forward-only reading and there is no way to add to it.
I've changed my strategy and used the JToken.Parse
instead with a couple of visitors that work similar to the ExpressionVisitor
.
The first one of them is the JsonVisitor
that recursively rebuilds the tree and allows to intercept this process by overriding VisitProperty
:
public delegate JToken VisitJsonCallback(JToken token);
public class JsonVisitor
{
public static JToken Visit(JToken token, params JsonVisitor visitors)
{
return visitors.Aggregate(token, (current, visitor) => visitor.Visit(current));
}
public static VisitJsonCallback Create(params JsonVisitor visitors) => jToken => Visit(jToken, visitors);
public JToken Visit(JToken token)
{
return
token is JValue
? token
: VisitInternal(token, CreateJContainer(token.Type));
}
private JToken VisitInternal(JToken token, JContainer result)
{
if (token is JValue)
{
return token;
}
foreach (var element in token)
{
switch (element)
{
case JProperty property:
var visitedProperty = VisitProperty(property);
result.Add(visitedProperty);
break;
default:
result.Add(Visit(element));
break;
}
}
return result;
}
protected virtual JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name, Visit(property.Value));
}
private static JContainer CreateJContainer(JTokenType tokenType)
{
switch (tokenType)
{
case JTokenType.Object: return new JObject();
case JTokenType.Array: return new JArray();
default: throw new ArgumentOutOfRangeException($"Invalid type: {tokenType}");
}
}
}
Since I didn't have any other use cases yet, it's the only overridable API right now but I think it should be easy to extend it in future.
Then I have two more of them that cover both use-cases (here in the reverse order)
public class PropertyNameTrimmer : JsonVisitor
{
protected override JProperty VisitProperty(JProperty property)
{
return new JProperty(property.Name.Trim(), Visit(property.Value));
}
}
public class TypeResolver : JsonVisitor
{
private readonly string _typePropertyName;
private readonly Func<string, string> _resolveType;
public TypeResolver(string typePropertyName, Func<string, string> resolveType)
{
_typePropertyName = typePropertyName;
_resolveType = resolveType;
}
protected override JProperty VisitProperty(JProperty property)
{
return
property.Name == _typePropertyName
? new JProperty("$type", _resolveType(property.Value.Value<string>()))
: base.VisitProperty(property);
}
}
Example
I would use them by passing the result from one to the other:
void Main()
{
var json = @"{ ""$t"": ""MyType"", ""User "": ""John"", ""Nested"": { ""$t"": ""OtherType"", "" ZIP"": 12345 }, ""Numbers"": [1, 2, 3 ] }";
var jToken = JToken.Parse(json);
jToken.ToString().Dump("Original");
var propertyNameTrimmer = new PropertyNameTrimmer();
var typeResolver = new TypeResolver("$t", shortName => shortName + "_resolved");
var trimmed = propertyNameTrimmer.Visit(jToken);
trimmed.ToString().Dump(nameof(PropertyNameTrimmer));
var typeResolved = typeResolver.Visit(trimmed);
typeResolved.ToString().Dump(nameof(TypeResolver));
}
So calling them in this order produces:
Original
{
"$t": "MyType",
"User ": "John",
"Nested": {
"$t": "OtherType",
" ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
PropertyNameTrimmer - whitespaces removed from property names
{
"$t": "MyType",
"User": "John",
"Nested": {
"$t": "OtherType",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
TypeResolver - property names changed and types resolved
{
"$type": "MyType_resolved",
"User": "John",
"Nested": {
"$type": "OtherType_resolved",
"ZIP": 12345
},
"Numbers": [
1,
2,
3
]
}
How do you like this solution? Have I missed anything important (but null-checks) and can I improve this in any way?
c# json json.net visitor-pattern
c# json json.net visitor-pattern
edited yesterday
asked 2 days ago
t3chb0t
33.8k746108
33.8k746108
Your visitor looks fine for what it does, but why rewrite property names instead of throwing an exception:"Unknown property: 'User ' at position ..."
? That also catches other problems like typos ("Usr"
) and case differences ("Zip"
), which are difficult to auto-correct due to ambiguity.
– Pieter Witvoet
yesterday
@PieterWitvoet yeah, it's a tough decision and I actually wasn't sure (and I'm still not) which one would be better, fixing or throwing exceptions. I was also going to allow dashes in property names that I would rewrite toC#
valid names. Typos are difficult to handle anyway because if a property is optional it's hard to say whether it's something else or a typo. I guess I cannot eliminate all mistakes but at least reduce the probability. Btw, json is case-insensitive.
– t3chb0t
yesterday
@PieterWitvoet for a complete validation I'll probably should use json-schema but I'm not sure about its license and whether I could use it at work... most likely not so I'm not even trying but even when using json-schema I still need to rewrite some parts of it ;-)
– t3chb0t
yesterday
JSON isn't case-insensitive, but I see what you mean - Json.NET will try to find an exact match, but falls back to a case-insensitive check. Either way, it looks like passing aJsonSerializerSettings
instance withMissingMemberHandling
set toError
should do the trick.
– Pieter Witvoet
yesterday
@PieterWitvoet ok, it looks like you're correct with the case sensitivity, however, I'm glad nobody takes this rule serious, it'd break the entire internet if it suddenly would be respected - I find this rule is pretty stupid ;-]
– t3chb0t
yesterday
|
show 1 more comment
Your visitor looks fine for what it does, but why rewrite property names instead of throwing an exception:"Unknown property: 'User ' at position ..."
? That also catches other problems like typos ("Usr"
) and case differences ("Zip"
), which are difficult to auto-correct due to ambiguity.
– Pieter Witvoet
yesterday
@PieterWitvoet yeah, it's a tough decision and I actually wasn't sure (and I'm still not) which one would be better, fixing or throwing exceptions. I was also going to allow dashes in property names that I would rewrite toC#
valid names. Typos are difficult to handle anyway because if a property is optional it's hard to say whether it's something else or a typo. I guess I cannot eliminate all mistakes but at least reduce the probability. Btw, json is case-insensitive.
– t3chb0t
yesterday
@PieterWitvoet for a complete validation I'll probably should use json-schema but I'm not sure about its license and whether I could use it at work... most likely not so I'm not even trying but even when using json-schema I still need to rewrite some parts of it ;-)
– t3chb0t
yesterday
JSON isn't case-insensitive, but I see what you mean - Json.NET will try to find an exact match, but falls back to a case-insensitive check. Either way, it looks like passing aJsonSerializerSettings
instance withMissingMemberHandling
set toError
should do the trick.
– Pieter Witvoet
yesterday
@PieterWitvoet ok, it looks like you're correct with the case sensitivity, however, I'm glad nobody takes this rule serious, it'd break the entire internet if it suddenly would be respected - I find this rule is pretty stupid ;-]
– t3chb0t
yesterday
Your visitor looks fine for what it does, but why rewrite property names instead of throwing an exception:
"Unknown property: 'User ' at position ..."
? That also catches other problems like typos ("Usr"
) and case differences ("Zip"
), which are difficult to auto-correct due to ambiguity.– Pieter Witvoet
yesterday
Your visitor looks fine for what it does, but why rewrite property names instead of throwing an exception:
"Unknown property: 'User ' at position ..."
? That also catches other problems like typos ("Usr"
) and case differences ("Zip"
), which are difficult to auto-correct due to ambiguity.– Pieter Witvoet
yesterday
@PieterWitvoet yeah, it's a tough decision and I actually wasn't sure (and I'm still not) which one would be better, fixing or throwing exceptions. I was also going to allow dashes in property names that I would rewrite to
C#
valid names. Typos are difficult to handle anyway because if a property is optional it's hard to say whether it's something else or a typo. I guess I cannot eliminate all mistakes but at least reduce the probability. Btw, json is case-insensitive.– t3chb0t
yesterday
@PieterWitvoet yeah, it's a tough decision and I actually wasn't sure (and I'm still not) which one would be better, fixing or throwing exceptions. I was also going to allow dashes in property names that I would rewrite to
C#
valid names. Typos are difficult to handle anyway because if a property is optional it's hard to say whether it's something else or a typo. I guess I cannot eliminate all mistakes but at least reduce the probability. Btw, json is case-insensitive.– t3chb0t
yesterday
@PieterWitvoet for a complete validation I'll probably should use json-schema but I'm not sure about its license and whether I could use it at work... most likely not so I'm not even trying but even when using json-schema I still need to rewrite some parts of it ;-)
– t3chb0t
yesterday
@PieterWitvoet for a complete validation I'll probably should use json-schema but I'm not sure about its license and whether I could use it at work... most likely not so I'm not even trying but even when using json-schema I still need to rewrite some parts of it ;-)
– t3chb0t
yesterday
JSON isn't case-insensitive, but I see what you mean - Json.NET will try to find an exact match, but falls back to a case-insensitive check. Either way, it looks like passing a
JsonSerializerSettings
instance with MissingMemberHandling
set to Error
should do the trick.– Pieter Witvoet
yesterday
JSON isn't case-insensitive, but I see what you mean - Json.NET will try to find an exact match, but falls back to a case-insensitive check. Either way, it looks like passing a
JsonSerializerSettings
instance with MissingMemberHandling
set to Error
should do the trick.– Pieter Witvoet
yesterday
@PieterWitvoet ok, it looks like you're correct with the case sensitivity, however, I'm glad nobody takes this rule serious, it'd break the entire internet if it suddenly would be respected - I find this rule is pretty stupid ;-]
– t3chb0t
yesterday
@PieterWitvoet ok, it looks like you're correct with the case sensitivity, however, I'm glad nobody takes this rule serious, it'd break the entire internet if it suddenly would be respected - I find this rule is pretty stupid ;-]
– t3chb0t
yesterday
|
show 1 more comment
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208641%2fchaining-json-transformations-with-visitors%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Your visitor looks fine for what it does, but why rewrite property names instead of throwing an exception:
"Unknown property: 'User ' at position ..."
? That also catches other problems like typos ("Usr"
) and case differences ("Zip"
), which are difficult to auto-correct due to ambiguity.– Pieter Witvoet
yesterday
@PieterWitvoet yeah, it's a tough decision and I actually wasn't sure (and I'm still not) which one would be better, fixing or throwing exceptions. I was also going to allow dashes in property names that I would rewrite to
C#
valid names. Typos are difficult to handle anyway because if a property is optional it's hard to say whether it's something else or a typo. I guess I cannot eliminate all mistakes but at least reduce the probability. Btw, json is case-insensitive.– t3chb0t
yesterday
@PieterWitvoet for a complete validation I'll probably should use json-schema but I'm not sure about its license and whether I could use it at work... most likely not so I'm not even trying but even when using json-schema I still need to rewrite some parts of it ;-)
– t3chb0t
yesterday
JSON isn't case-insensitive, but I see what you mean - Json.NET will try to find an exact match, but falls back to a case-insensitive check. Either way, it looks like passing a
JsonSerializerSettings
instance withMissingMemberHandling
set toError
should do the trick.– Pieter Witvoet
yesterday
@PieterWitvoet ok, it looks like you're correct with the case sensitivity, however, I'm glad nobody takes this rule serious, it'd break the entire internet if it suddenly would be respected - I find this rule is pretty stupid ;-]
– t3chb0t
yesterday