Service Stack is double escaping?

We use nested JsonObjects in our DTOs in order to have a dynamic object, Sometimes customers post data like “” but in this case we run into an issue that:

var o = new JsonObject();
o.Add("url", @"http:\/\/");

we will get (escaped backslash):


instead of:

or better
{"url":""} like with Console.WriteLine(o["url"])

is there a way to avoid this issue?

It’s being escaped correctly as it needs to include the back slashes contained in the string:


Is the same as:


yes sounds logical, but if we use ExpandoObject instead of JsonObject we doesn’t run in this issue:

var b = @"{""url"":""http:\/\/""}";
var jObj = ServiceStack.Text.JsonSerializer.DeserializeFromString<ExpandoObject>(b);

output is


What issue, if "http:\/\/" unescapes to c# string, if you don’t want the back slashes don’t add them, they’re already not needed.

… normally I expect that if someone sends data with e.g. “” to our REST API the minimum is that after deserialization and working with the deserialized data and then serialize it back to Json… I at least expect to get the same data back => “” ?

I think you mean that the contents in JsonObject are stored unescaped, that’s just how it works, you’d use the APIs to retrieve escaped values from it, e.g:

var url = jsonObj.Get("url");

Otherwise you can just deserialize it into a string dictionary:

var strDict = b.FromJson<Dictionary<string,string>>();

ok b.FromJson<Dictionary<string,string>>(); returns a Json string without backslash with e.g.

var jObjDict = b.FromJson<Dictionary<string, string>>();

but we have DTOs with nested JsonObject so wtih


we run into the same issue…

…the nested JsonObject in our DTOs are like pass through parameter so if a consumer saves an object via our REST API, he would like to get the same thing back again …

REST API POST "http:\/\/" 
=>  REST API GET "http:\/\/" and not REST API GET "http:\\/\\/"

We have to consider that slashes are passed escaped to our API, since escaping slashes is vailid (but optional). I think the underlying problem is that consecutive (de-)serializaition via JsonObject

var s0 = @"{""escapeTest"":"" / \/ \""test\"" \\ ""}";
var s1 = JsonSerializer.SerializeToString(JsonSerializer.DeserializeFromString<JsonObject>(s0));
var s2 = JsonSerializer.SerializeToString(JsonSerializer.DeserializeFromString<JsonObject>(s1));
var s3 = JsonSerializer.SerializeToString(JsonSerializer.DeserializeFromString<JsonObject>(s2));

results in backslashes multiplied by a power of 2:

{"escapeTest":" / \/ \"test\" \\ "}
{"escapeTest":" / \\/ \\\"test\\\" \\\\ "}
{"escapeTest":" / \\\\/ \\\\\\\"test\\\\\\\" \\\\\\\\ "}
{"escapeTest":" / \\\\\\\\/ \\\\\\\\\\\\\\\"test\\\\\\\\\\\\\\\" \\\\\\\\\\\\\\\\ "}

Right you don’t want to be using JsonObject for serialization, it’s not a dynamic object, it’s a wrapper around Dictionary<string,string> that holds unescaped string values that you can choose to access both the escaped an unescaped values out with obj.Get() and obj.GetUnescaped().

You should use Dictionary<string,string> where it’s appropriate. ServiceStack also supports object types which is more “dynamic” since it will return the actual .NET Data Structure instead of coercing everything into a Dictionary<string,string> however using dynamic object is poor API design that ideally should not be your Service Contracts.

but when using object instead of JsonObject:

var b = @"{""url"":""http:\/\/""}";
var jObj = ServiceStack.Text.JsonSerializer.DeserializeFromString<Object>(b);

we get:



{"url":"http:\/\/"}  or {"url":""}

It works differently in ServiceStack Services because it replaces the implementation of ServiceStack.Text object handling with JS Utils which is in ServiceStack.Common.

You can test it with:

var obj = JSON.parse(@"{""url"":""http:\/\/""}") as Dictionary<string,object>;

But you’ll still get unescaped string, i.e:


To hookup the different serialization behavior in ServiceStack.Text:

JS.Configure(); // replace object handling

// JsonSerializer.

JS.UnConfigure(); // restore object handling

ok thanks now it looks better already

Hi, I’ve one more question is there any way to get an Exception instead of 0 after deserialize to Dictionary<string,object> in the following example (number with 2 decimal points ):

var obj = JSON.parse(@"{""test"":23.34.3333}") as Dictionary<string,object>;

Should now throw on invalid numbers from this commit.

This change is available from the latest v5.5.1 that’s now available on MyGet.

Thank you very much… good job