String without quotes?

Apr 28, 2008 at 2:55 PM
Is there any easy way to serialize out a string without quotes? This way, it would basically point to another variable / function that I've defined elsewhere in the javascript. So:
"event":myfunction instead of "event":"myfunction"

Or is there an easy way to get javascript to see "myfunction" as a function call?
Coordinator
May 3, 2008 at 3:37 AM
There is WriteRaw on the JsonWriter and the Identifier object for when you are serializing. This isn't an area that I have looked at closely so you may very well encounter bugs.
Jul 6, 2010 at 11:01 PM

I also wanted to find a way to avoid the quotes being generated around javascript functions, but unfortunately could not find any way of doing it without modifying the existing code.

When I experimented and debugged the source code (which I tonight retrieved from SVN trunk), I ran into the method "JsonTextWriter.WriteValue(string)"  which uses a hardcoded invocation of "JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true);"

The last bool parameter specifies "appendDelimiters" which seem to be the code that adds the quotes.

By doing a workaround hack, that method can be overloaded/parameterized, and then your own JsonConverter can use your own converter implementation to avoid writing the quotes by using false as the appendDelimiters value.

Here is some code to illustrate what I mean:

 

    public class JsonConverterNotSurroundingJavascriptContentWithQuotations : JsonConverter {
        public override bool CanConvert(Type objectType) {
            return objectType.Equals(typeof(JavascriptContent));
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
            writer.WriteValue(value.ToString(), false);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
            throw new NotImplementedException();
        }
    }

    public class JavascriptContent {
        private readonly string _javascriptString;
        public JavascriptContent(string javascriptString) {
            _javascriptString = javascriptString;
        }
        public override string ToString() {
            return _javascriptString;
        }
    }

    public static class StringExtensions {
        public static JavascriptContent GetAsJavaScriptContentNotBeingSurroundedByQuotes(this string javascriptString) {
            return new JavascriptContent(javascriptString);
        }
    }

Below is the code I "had to" (?) change in the existing source files:

 

public class JsonTextWriter : JsonWriter {
	...
    public override void WriteValue(string value)
    {
        // The standard implementation uses the hardcoded "true" value as parameter to "JavaScriptUtils.WriteEscapedJavaScriptString"
        WriteValue(value, true);
    }

    // My own overloaded version of the WriteValue method
    public override void WriteValue(string value, bool appendDelimiters)
    {
        base.WriteValue(value);
        if (value == null)
            WriteValueInternal(JsonConvert.Null, JsonToken.Null);
        else
            JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, appendDelimiters);
    }


public abstract class JsonWriter : IDisposable {
	...
    public virtual void WriteValue(string value)
    {
      AutoComplete(JsonToken.String);
    }

    public virtual void WriteValue(string value, bool appendDelimiters)
    {
        AutoComplete(JsonToken.String); // ?
    }

Below is an example class that uses the above used JavaScriptContent type in some of its properties:

 

    public class MyJsonClass
{
public string MyString { get; set; }
public DateTime MyDateTime { get; set; }
public decimal MyDecimal { get; set; }
public object[] MyArrayWithDifferentTypes { get; set; }
public int MyInteger { get; set; }
public bool MyBool { get; set; }
public JavascriptContent MyJavascriptFunctionLiteral { get; set; }
public JavascriptContent MyFunctionPointer { get; set; }
}

And below is a usage example from within some method somewhere (e.g. from within a Main method):

            MyJsonClass myJsonClass = new MyJsonClass();
            myJsonClass.MyString = "ABC";
            myJsonClass.MyInteger = 123;
            myJsonClass.MyBool = true;
            myJsonClass.MyDecimal = 3.99M;
            myJsonClass.MyDateTime = new DateTime(2008, 12, 28);

            myJsonClass.MyJavascriptFunctionLiteral = "function myFunction() { doStuff('abc'); }".GetAsJavaScriptContentNotBeingSurroundedByQuotes();
            myJsonClass.MyFunctionPointer = "someFunctionPointerWhichShouldNotBeSurroundedWithQuotes".GetAsJavaScriptContentNotBeingSurroundedByQuotes();

            myJsonClass.MyArrayWithDifferentTypes = new object[]
            {
                "QWERTY", 
                98765, 
                false, 
                "function myJavscriptFunction(myId) { var x = 'zxcvb'; var y = x + x; return y + myId; } ".GetAsJavaScriptContentNotBeingSurroundedByQuotes()
            };

            string json = JsonConvert.SerializeObject(myJsonClass, Formatting.Indented, new JsonConverterNotSurroundingJavascriptContentWithQuotations());

            Console.WriteLine("json: " + json);

When the above code is executed, the following output is produced:

json: {
  "MyString": "ABC",
  "MyDateTime": "\/Date(1230418800000+0100)\/",
  "MyDecimal": 3.99,
  "MyArrayWithDifferentTypes": [
    "QWERTY",
    98765,
    false,
    function myJavscriptFunction(myId) { var x = 'zxcvb'; var y = x + x; return y + myId; } 
  ],
  "MyInteger": 123,
  "MyBool": true,
  "MyJavascriptFunctionLiteral": function myFunction() { doStuff('abc'); },
  "MyFunctionPointer": someFunctionPointerWhichShouldNotBeSurroundedWithQuotes
}

The above code seem to work (i.e. no quotes around the javascript code)  as far I can tell with my (not too comprehensive) experiments, but I would like to find a better solution, and in particular a solution that will not require modifications to the existing codebase (such as the above modifications in JsonTextWriter and its base type) if someone can suggest something ?

/ Tomas

 

Sep 22, 2010 at 7:07 PM

It should be possible to write unquoted values using just a converter class via the JsonWriter's WriteRawValue method. Then you can apply the converter class in the JsonConverter attribute for specific members.

(untested code)

 

public class JsFunctionConverter : Newtonsoft.Json.JsonConverter
{

    public override bool CanConvert(System.Type objectType)
    {
        return true;
    }

    public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
    {
        return existingValue;
    }

    public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
    {
        writer.WriteRawValue(value);
    }
}

 

public class MyJsonClass
{
public string MyString { get; set; }
public DateTime MyDateTime { get; set; }
public decimal MyDecimal { get; set; }
public object[] MyArrayWithDifferentTypes { get; set; }
public int MyInteger { get; set; }
public bool MyBool { get; set; }
        [JsonConverter(typeof(JsFunctionConverter))]
        public JavascriptContent MyJavascriptFunctionLiteral { get; set; }

      [JsonConverter(typeof(JsFunctionConverter))]
      public JavascriptContent MyFunctionPointer { get; set; }
}
Coordinator
Sep 23, 2010 at 1:44 AM

Since the initial post a JRaw property will be written out as a raw value.

Oct 5, 2010 at 9:53 PM

I tried to use JRaw as follows and received an exception. Is this the wrong approach?

p.s. Thanks for this great library.

  Public Class Thing       
        <JsonConverter(GetType(Newtonsoft.Json.Linq.JRaw))> _
        Public name As String
  End Class

 

Serialized via  

JsonConvert.SerializeObject(New Thing)


resulted in

 

Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.

[MissingMethodException: No parameterless constructor defined for this object.]
   System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) +0
   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) +86
   System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache) +230
   System.Activator.CreateInstance(Type type, Boolean nonPublic) +67
   Newtonsoft.Json.JsonConverterAttribute.CreateJsonConverterInstance(Type converterType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\JsonConverterAttribute.cs:43

[Exception: Error creating Newtonsoft.Json.Linq.JRaw]
   Newtonsoft.Json.JsonConverterAttribute.CreateJsonConverterInstance(Type converterType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\JsonConverterAttribute.cs:47
   Newtonsoft.Json.Serialization.JsonTypeReflector.GetJsonConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\JsonTypeReflector.cs:139
   Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperty(JsonObjectContract contract, MemberInfo member) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:614
   Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperties(JsonObjectContract contract) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:580
   Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:270
   Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:492
   Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:179
   Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.GetContractSafe(Object value) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalWriter.cs:79
   Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalWriter.cs:62
   Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\JsonSerializer.cs:451
   Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting, JsonSerializerSettings settings) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\JsonConvert.cs:591
   Newtonsoft.Json.JsonConvert.SerializeObject(Object value) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\JsonConvert.cs:528