-Added StringEscapeHandling with options to escape HTML and non-ASCII characters
-Added feature to deserialize ISet<T> properties as HashSet<T> -Fixed ReferenceLoopHandling not being used when serializing ISerializable and dynamic values
This commit is contained in:
@@ -841,6 +841,69 @@ _____'propertyName': NaN
|
||||
Assert.AreEqual(@"""2000-01-01T01:01:01Z""", sw.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HtmlStringEscapeHandling()
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
JsonTextWriter writer = new JsonTextWriter(sw)
|
||||
{
|
||||
StringEscapeHandling = StringEscapeHandling.EscapeHtml
|
||||
};
|
||||
|
||||
string script = @"<script type=""text/javascript"">alert('hi');</script>";
|
||||
|
||||
writer.WriteValue(script);
|
||||
|
||||
string json = sw.ToString();
|
||||
|
||||
Assert.AreEqual(@"""\u003cscript type=\u0022text/javascript\u0022\u003ealert(\u0027hi\u0027);\u003c/script\u003e""", json);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
|
||||
Assert.AreEqual(script, reader.ReadAsString());
|
||||
|
||||
//Console.WriteLine(HttpUtility.HtmlEncode(script));
|
||||
|
||||
//System.Web.Script.Serialization.JavaScriptSerializer s = new System.Web.Script.Serialization.JavaScriptSerializer();
|
||||
//Console.WriteLine(s.Serialize(new { html = script }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NonAsciiStringEscapeHandling()
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
JsonTextWriter writer = new JsonTextWriter(sw)
|
||||
{
|
||||
StringEscapeHandling = StringEscapeHandling.EscapeNonAscii
|
||||
};
|
||||
|
||||
string unicode = "\u5f20";
|
||||
|
||||
writer.WriteValue(unicode);
|
||||
|
||||
string json = sw.ToString();
|
||||
|
||||
Assert.AreEqual(8, json.Length);
|
||||
Assert.AreEqual(@"""\u5f20""", json);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
|
||||
Assert.AreEqual(unicode, reader.ReadAsString());
|
||||
|
||||
sw = new StringWriter();
|
||||
writer = new JsonTextWriter(sw)
|
||||
{
|
||||
StringEscapeHandling = StringEscapeHandling.Default
|
||||
};
|
||||
|
||||
writer.WriteValue(unicode);
|
||||
|
||||
json = sw.ToString();
|
||||
|
||||
Assert.AreEqual(3, json.Length);
|
||||
Assert.AreEqual("\"\u5f20\"", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteEndOnProperty()
|
||||
{
|
||||
|
||||
@@ -291,6 +291,48 @@ namespace Newtonsoft.Json.Tests
|
||||
Console.WriteLine("XML: " + watch.Elapsed.TotalSeconds);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeString()
|
||||
{
|
||||
string text = @"The general form of an HTML element is therefore: <tag attribute1=""value1"" attribute2=""value2"">content</tag>.
|
||||
Some HTML elements are defined as empty elements and take the form <tag attribute1=""value1"" attribute2=""value2"" >.
|
||||
Empty elements may enclose no content, for instance, the BR tag or the inline IMG tag.
|
||||
The name of an HTML element is the name used in the tags.
|
||||
Note that the end tag's name is preceded by a slash character, ""/"", and that in empty elements the end tag is neither required nor allowed.
|
||||
If attributes are not mentioned, default values are used in each case.
|
||||
|
||||
The general form of an HTML element is therefore: <tag attribute1=""value1"" attribute2=""value2"">content</tag>.
|
||||
Some HTML elements are defined as empty elements and take the form <tag attribute1=""value1"" attribute2=""value2"" >.
|
||||
Empty elements may enclose no content, for instance, the BR tag or the inline IMG tag.
|
||||
The name of an HTML element is the name used in the tags.
|
||||
Note that the end tag's name is preceded by a slash character, ""/"", and that in empty elements the end tag is neither required nor allowed.
|
||||
If attributes are not mentioned, default values are used in each case.
|
||||
|
||||
The general form of an HTML element is therefore: <tag attribute1=""value1"" attribute2=""value2"">content</tag>.
|
||||
Some HTML elements are defined as empty elements and take the form <tag attribute1=""value1"" attribute2=""value2"" >.
|
||||
Empty elements may enclose no content, for instance, the BR tag or the inline IMG tag.
|
||||
The name of an HTML element is the name used in the tags.
|
||||
Note that the end tag's name is preceded by a slash character, ""/"", and that in empty elements the end tag is neither required nor allowed.
|
||||
If attributes are not mentioned, default values are used in each case.
|
||||
";
|
||||
|
||||
int interations = 1000;
|
||||
|
||||
TimeOperation(() =>
|
||||
{
|
||||
string json = null;
|
||||
for (int i = 0; i < interations; i++)
|
||||
{
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(text) ?? 16))
|
||||
{
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(w, text, '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}, "New");
|
||||
}
|
||||
|
||||
private void SerializeSize(object value)
|
||||
{
|
||||
// this is extremely slow with 5000 interations
|
||||
|
||||
@@ -76,5 +76,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.5.10.15512")]
|
||||
[assembly: AssemblyFileVersion("4.5.10.15518")]
|
||||
#endif
|
||||
|
||||
@@ -7154,6 +7154,68 @@ Parameter name: value",
|
||||
Assert.IsNull(c2.MyNullableDecimal);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(PORTABLE || NET20 || NET35 || WINDOWS_PHONE)
|
||||
[Test]
|
||||
public void HashSetInterface()
|
||||
{
|
||||
ISet<string> s1 = new HashSet<string>(new[] {"1", "two", "III"});
|
||||
|
||||
string json = JsonConvert.SerializeObject(s1);
|
||||
|
||||
ISet<string> s2 = JsonConvert.DeserializeObject<ISet<string>>(json);
|
||||
|
||||
Assert.AreEqual(s1.Count, s2.Count);
|
||||
foreach (string s in s1)
|
||||
{
|
||||
Assert.IsTrue(s2.Contains(s));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public class NewEmployee : Employee
|
||||
{
|
||||
public int Age { get; set; }
|
||||
|
||||
public bool ShouldSerializeName()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldSerializeInheritedClassTest()
|
||||
{
|
||||
NewEmployee joe = new NewEmployee();
|
||||
joe.Name = "Joe Employee";
|
||||
joe.Age = 100;
|
||||
|
||||
Employee mike = new Employee();
|
||||
mike.Name = "Mike Manager";
|
||||
mike.Manager = mike;
|
||||
|
||||
joe.Manager = mike;
|
||||
|
||||
//StringWriter sw = new StringWriter();
|
||||
|
||||
//XmlSerializer x = new XmlSerializer(typeof(NewEmployee));
|
||||
//x.Serialize(sw, joe);
|
||||
|
||||
//Console.WriteLine(sw);
|
||||
|
||||
//JavaScriptSerializer s = new JavaScriptSerializer();
|
||||
//Console.WriteLine(s.Serialize(new {html = @"<script>hi</script>; & ! ^ * ( ) ! @ # $ % ^ ' "" - , . / ; : [ { } ] ; ' - _ = + ? ` ~ \ |"}));
|
||||
|
||||
string json = JsonConvert.SerializeObject(joe, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""Age"": 100,
|
||||
""Name"": ""Joe Employee"",
|
||||
""Manager"": {
|
||||
""Name"": ""Mike Manager""
|
||||
}
|
||||
}", json);
|
||||
}
|
||||
}
|
||||
|
||||
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if !NETFX_CORE
|
||||
using NUnit.Framework;
|
||||
@@ -31,6 +32,11 @@ using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
|
||||
using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
|
||||
using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
|
||||
#endif
|
||||
#if !(NET20 || NET35 || WINDOWS_PHONE)
|
||||
using System.Dynamic;
|
||||
#endif
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json.Tests.Linq;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.Serialization
|
||||
{
|
||||
@@ -142,6 +148,126 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
]
|
||||
}", json);
|
||||
}
|
||||
|
||||
#if !(PORTABLE || SILVERLIGHT)
|
||||
public class MainClass : ISerializable
|
||||
{
|
||||
public ChildClass Child { get; set; }
|
||||
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
info.AddValue("Child", Child);
|
||||
}
|
||||
}
|
||||
|
||||
public class ChildClass : ISerializable
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public MainClass Parent { get; set; }
|
||||
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
info.AddValue("Parent", Parent);
|
||||
info.AddValue("Name", Name);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ErrorISerializableCyclicReferenceLoop()
|
||||
{
|
||||
var main = new MainClass();
|
||||
var child = new ChildClass();
|
||||
|
||||
child.Name = "Child1";
|
||||
child.Parent = main; // Obvious Circular Reference
|
||||
|
||||
main.Child = child;
|
||||
|
||||
var settings =
|
||||
new JsonSerializerSettings();
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Self referencing loop detected with type 'Newtonsoft.Json.Tests.Serialization.ReferenceLoopHandlingTests+MainClass'. Path 'Child'.",
|
||||
() => JsonConvert.SerializeObject(main, settings));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IgnoreISerializableCyclicReferenceLoop()
|
||||
{
|
||||
var main = new MainClass();
|
||||
var child = new ChildClass();
|
||||
|
||||
child.Name = "Child1";
|
||||
child.Parent = main; // Obvious Circular Reference
|
||||
|
||||
main.Child = child;
|
||||
|
||||
var settings =
|
||||
new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
|
||||
|
||||
var c = JsonConvert.SerializeObject(main, settings);
|
||||
Assert.AreEqual(@"{""Child"":{""Name"":""Child1""}}", c);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(PORTABLE || NET20 || NET35 || WINDOWS_PHONE)
|
||||
public class DictionaryDynamicObject : DynamicObject
|
||||
{
|
||||
public IDictionary<string, object> Values { get; private set; }
|
||||
|
||||
public DictionaryDynamicObject()
|
||||
{
|
||||
Values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
Values[binder.Name] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
return Values.TryGetValue(binder.Name, out result);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return Values.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ErrorDynamicCyclicReferenceLoop()
|
||||
{
|
||||
dynamic parent = new DictionaryDynamicObject();
|
||||
dynamic child = new DictionaryDynamicObject();
|
||||
parent.child = child;
|
||||
child.parent = parent;
|
||||
|
||||
var settings = new JsonSerializerSettings();
|
||||
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
"Self referencing loop detected with type 'Newtonsoft.Json.Tests.Serialization.ReferenceLoopHandlingTests+DictionaryDynamicObject'. Path 'child'.",
|
||||
() => JsonConvert.SerializeObject(parent, settings));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IgnoreDynamicCyclicReferenceLoop()
|
||||
{
|
||||
dynamic parent = new DictionaryDynamicObject();
|
||||
dynamic child = new DictionaryDynamicObject();
|
||||
parent.child = child;
|
||||
parent.name = "parent";
|
||||
child.parent = parent;
|
||||
child.name = "child";
|
||||
|
||||
var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
|
||||
|
||||
var c = JsonConvert.SerializeObject(parent, settings);
|
||||
Assert.AreEqual(@"{""child"":{""name"":""child""},""name"":""parent""}", c);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public class PropertyItemReferenceLoopHandling
|
||||
|
||||
@@ -556,11 +556,14 @@ namespace Newtonsoft.Json
|
||||
/// Converts the <see cref="String"/> to its JSON string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
/// <param name="delimter">The string delimiter character.</param>
|
||||
/// <param name="delimiter">The string delimiter character.</param>
|
||||
/// <returns>A JSON string representation of the <see cref="String"/>.</returns>
|
||||
public static string ToString(string value, char delimter)
|
||||
public static string ToString(string value, char delimiter)
|
||||
{
|
||||
return JavaScriptUtils.ToEscapedJavaScriptString(value, delimter, true);
|
||||
if (delimiter != '"' && delimiter != '\'')
|
||||
throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
|
||||
|
||||
return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -206,11 +206,22 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
InternalWritePropertyName(name);
|
||||
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName);
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, GetCharEscapeFlags(), StringEscapeHandling);
|
||||
|
||||
_writer.Write(':');
|
||||
}
|
||||
|
||||
private bool[] GetCharEscapeFlags()
|
||||
{
|
||||
if (StringEscapeHandling == StringEscapeHandling.EscapeHtml)
|
||||
return JavaScriptUtils.HtmlCharEscapeFlags;
|
||||
|
||||
if (_quoteChar == '"')
|
||||
return JavaScriptUtils.DoubleQuoteCharEscapeFlags;
|
||||
|
||||
return JavaScriptUtils.SingleQuoteCharEscapeFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes indent characters.
|
||||
/// </summary>
|
||||
@@ -294,7 +305,7 @@ namespace Newtonsoft.Json
|
||||
if (value == null)
|
||||
WriteValueInternal(JsonConvert.Null, JsonToken.Null);
|
||||
else
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true);
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true, GetCharEscapeFlags(), StringEscapeHandling);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -209,6 +209,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private DateFormatHandling _dateFormatHandling;
|
||||
private DateTimeZoneHandling _dateTimeZoneHandling;
|
||||
private StringEscapeHandling _stringEscapeHandling;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates how JSON text output is formatted.
|
||||
@@ -229,7 +230,7 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set how <see cref="DateTime"/> time zones are handling when writing JSON.
|
||||
/// Get or set how <see cref="DateTime"/> time zones are handling when writing JSON text.
|
||||
/// </summary>
|
||||
public DateTimeZoneHandling DateTimeZoneHandling
|
||||
{
|
||||
@@ -237,6 +238,15 @@ namespace Newtonsoft.Json
|
||||
set { _dateTimeZoneHandling = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set how strings are escaped when writing JSON text.
|
||||
/// </summary>
|
||||
public StringEscapeHandling StringEscapeHandling
|
||||
{
|
||||
get { return _stringEscapeHandling; }
|
||||
set { _stringEscapeHandling = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <c>JsonWriter</c> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
<Compile Include="Serialization\JsonDynamicContract.cs" />
|
||||
<Compile Include="Serialization\MemoryTraceWriter.cs" />
|
||||
<Compile Include="StreamingContext.cs" />
|
||||
<Compile Include="StringEscapeHandling.cs" />
|
||||
<Compile Include="Utilities\LinqBridge.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
<Compile Include="Linq\JPropertyDescriptor.cs" />
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
<Compile Include="Serialization\JsonContainerContract.cs" />
|
||||
<Compile Include="Serialization\MemoryTraceWriter.cs" />
|
||||
<Compile Include="StreamingContext.cs" />
|
||||
<Compile Include="StringEscapeHandling.cs" />
|
||||
<Compile Include="TraceLevel.cs" />
|
||||
<Compile Include="Utilities\DynamicProxy.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||
<Compile Include="StreamingContext.cs" />
|
||||
<Compile Include="StringEscapeHandling.cs" />
|
||||
<Compile Include="TraceLevel.cs" />
|
||||
<Compile Include="TypeNameHandling.cs" />
|
||||
<Compile Include="Utilities\Base64Encoder.cs" />
|
||||
|
||||
@@ -197,6 +197,7 @@
|
||||
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||
<Compile Include="StreamingContext.cs" />
|
||||
<Compile Include="StringEscapeHandling.cs" />
|
||||
<Compile Include="TraceLevel.cs" />
|
||||
<Compile Include="TypeNameHandling.cs" />
|
||||
<Compile Include="Utilities\Base64Encoder.cs" />
|
||||
|
||||
@@ -170,6 +170,7 @@
|
||||
<Compile Include="Serialization\OnErrorAttribute.cs" />
|
||||
<Compile Include="Serialization\ReflectionValueProvider.cs" />
|
||||
<Compile Include="StreamingContext.cs" />
|
||||
<Compile Include="StringEscapeHandling.cs" />
|
||||
<Compile Include="TraceLevel.cs" />
|
||||
<Compile Include="TypeNameHandling.cs" />
|
||||
<Compile Include="Utilities\Base64Encoder.cs" />
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
<Compile Include="Serialization\ITraceWriter.cs" />
|
||||
<Compile Include="Serialization\JsonContainerContract.cs" />
|
||||
<Compile Include="Serialization\MemoryTraceWriter.cs" />
|
||||
<Compile Include="StringEscapeHandling.cs" />
|
||||
<Compile Include="Utilities\DynamicProxy.cs" />
|
||||
<Compile Include="Linq\JPath.cs" />
|
||||
<Compile Include="Linq\JRaw.cs" />
|
||||
|
||||
@@ -90,7 +90,7 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.5.10.15512")]
|
||||
[assembly: AssemblyFileVersion("4.5.10.15518")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -5,8 +5,19 @@ using DiagnosticsTrace = System.Diagnostics.Trace;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a trace writer that writes to the application's <see cref="TraceListener"/> instances.
|
||||
/// </summary>
|
||||
public class DiagnosticsTraceWriter : ITraceWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="TraceLevel"/> that will be used to filter the trace messages passed to the writer.
|
||||
/// For example a filter level of <code>Info</code> will exclude <code>Verbose</code> messages and include <code>Info</code>,
|
||||
/// <code>Warning</code> and <code>Error</code> messages.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The <see cref="TraceLevel"/> that will be used to filter the trace messages passed to the writer.
|
||||
/// </value>
|
||||
public TraceLevel LevelFilter { get; set; }
|
||||
|
||||
private TraceEventType GetTraceEventType(TraceLevel level)
|
||||
@@ -26,6 +37,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified trace level, message and optional exception.
|
||||
/// </summary>
|
||||
/// <param name="level">The <see cref="TraceLevel"/> at which to write this trace.</param>
|
||||
/// <param name="message">The trace message.</param>
|
||||
/// <param name="ex">The trace exception. This parameter is optional.</param>
|
||||
public void Trace(TraceLevel level, string message, Exception ex)
|
||||
{
|
||||
if (level == TraceLevel.Off)
|
||||
|
||||
@@ -85,9 +85,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
_isCollectionItemTypeNullableType = ReflectionUtils.IsNullableType(CollectionItemType);
|
||||
|
||||
if (IsTypeGenericCollectionInterface(UnderlyingType))
|
||||
{
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(List<>), CollectionItemType);
|
||||
}
|
||||
#if !(PORTABLE || NET20 || NET35 || WINDOWS_PHONE)
|
||||
else if (IsTypeGenericSetnterface(UnderlyingType))
|
||||
CreatedType = ReflectionUtils.MakeGenericType(typeof(HashSet<>), CollectionItemType);
|
||||
#endif
|
||||
|
||||
IsMultidimensionalArray = (UnderlyingType.IsArray && UnderlyingType.GetArrayRank() > 1);
|
||||
}
|
||||
@@ -152,5 +154,17 @@ namespace Newtonsoft.Json.Serialization
|
||||
|| genericDefinition == typeof(ICollection<>)
|
||||
|| genericDefinition == typeof(IEnumerable<>));
|
||||
}
|
||||
|
||||
#if !(PORTABLE || NET20 || NET35 || WINDOWS_PHONE)
|
||||
private bool IsTypeGenericSetnterface(Type type)
|
||||
{
|
||||
if (!type.IsGenericType())
|
||||
return false;
|
||||
|
||||
Type genericDefinition = type.GetGenericTypeDefinition();
|
||||
|
||||
return (genericDefinition == typeof(ISet<>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// <summary>
|
||||
/// Contract details for a <see cref="Type"/> used by the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
public class JsonISerializableContract : JsonContract
|
||||
public class JsonISerializableContract : JsonContainerContract
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the ISerializable object constructor.
|
||||
|
||||
@@ -682,8 +682,13 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
foreach (SerializationEntry serializationEntry in serializationInfo)
|
||||
{
|
||||
writer.WritePropertyName(serializationEntry.Name);
|
||||
SerializeValue(writer, serializationEntry.Value, GetContractSafe(serializationEntry.Value), null, null, member);
|
||||
JsonContract valueContract = GetContractSafe(serializationEntry.Value);
|
||||
|
||||
if (CheckForCircularReference(writer, serializationEntry.Value, null, valueContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(serializationEntry.Name);
|
||||
SerializeValue(writer, serializationEntry.Value, valueContract, null, contract, member);
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
@@ -736,12 +741,17 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
{
|
||||
try
|
||||
{
|
||||
string resolvedPropertyName = (contract.PropertyNameResolver != null)
|
||||
? contract.PropertyNameResolver(memberName)
|
||||
: memberName;
|
||||
JsonContract valueContract = GetContractSafe(memberValue);
|
||||
|
||||
writer.WritePropertyName(resolvedPropertyName);
|
||||
SerializeValue(writer, memberValue, GetContractSafe(memberValue), null, null, member);
|
||||
if (CheckForCircularReference(writer, memberValue, null, valueContract, contract, member))
|
||||
{
|
||||
string resolvedPropertyName = (contract.PropertyNameResolver != null)
|
||||
? contract.PropertyNameResolver(memberName)
|
||||
: memberName;
|
||||
|
||||
writer.WritePropertyName(resolvedPropertyName);
|
||||
SerializeValue(writer, memberValue, valueContract, null, contract, member);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -5,18 +5,39 @@ using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a trace writer that writes to memory. When the trace message limit is
|
||||
/// reached then old trace messages will be removed as new messages are added.
|
||||
/// </summary>
|
||||
public class MemoryTraceWriter : ITraceWriter
|
||||
{
|
||||
private readonly Queue<string> _traceMessages;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="TraceLevel"/> that will be used to filter the trace messages passed to the writer.
|
||||
/// For example a filter level of <code>Info</code> will exclude <code>Verbose</code> messages and include <code>Info</code>,
|
||||
/// <code>Warning</code> and <code>Error</code> messages.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The <see cref="TraceLevel"/> that will be used to filter the trace messages passed to the writer.
|
||||
/// </value>
|
||||
public TraceLevel LevelFilter { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MemoryTraceWriter"/> class.
|
||||
/// </summary>
|
||||
public MemoryTraceWriter()
|
||||
{
|
||||
LevelFilter = TraceLevel.Verbose;
|
||||
_traceMessages = new Queue<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified trace level, message and optional exception.
|
||||
/// </summary>
|
||||
/// <param name="level">The <see cref="TraceLevel"/> at which to write this trace.</param>
|
||||
/// <param name="message">The trace message.</param>
|
||||
/// <param name="ex">The trace exception. This parameter is optional.</param>
|
||||
public void Trace(TraceLevel level, string message, Exception ex)
|
||||
{
|
||||
string traceMessage = DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff") + " " + level.ToString("g") + " " + message;
|
||||
@@ -27,11 +48,21 @@ namespace Newtonsoft.Json.Serialization
|
||||
_traceMessages.Enqueue(traceMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumeration of the most recent trace messages.
|
||||
/// </summary>
|
||||
/// <returns>An enumeration of the most recent trace messages.</returns>
|
||||
public IEnumerable<string> GetTraceMessages()
|
||||
{
|
||||
return _traceMessages;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="String"/> of the most recent trace messages.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="String"/> of the most recent trace messages.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#region License
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies how strings are escaped when writing JSON text.
|
||||
/// </summary>
|
||||
public enum StringEscapeHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Only control characters (e.g. newline) are escaped.
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// All non-ASCII and control characters (e.g. newline) are escaped.
|
||||
/// </summary>
|
||||
EscapeNonAscii,
|
||||
/// <summary>
|
||||
/// HTML (<, >, &, ', ") and control characters (e.g. newline) are escaped.
|
||||
/// </summary>
|
||||
EscapeHtml
|
||||
}
|
||||
}
|
||||
@@ -30,14 +30,48 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
#if NET20
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal static class JavaScriptUtils
|
||||
{
|
||||
internal static readonly bool[] SingleQuoteCharEscapeFlags = new bool[128];
|
||||
internal static readonly bool[] DoubleQuoteCharEscapeFlags = new bool[128];
|
||||
internal static readonly bool[] HtmlCharEscapeFlags = new bool[128];
|
||||
|
||||
static JavaScriptUtils()
|
||||
{
|
||||
IList<char> escapeChars = new List<char>
|
||||
{
|
||||
'\n', '\r', '\t', '\\', '\f', '\b',
|
||||
};
|
||||
for (int i = 0; i < ' '; i++)
|
||||
{
|
||||
escapeChars.Add((char)i);
|
||||
}
|
||||
|
||||
foreach (var escapeChar in escapeChars.Union(new[] { '\'' }))
|
||||
{
|
||||
SingleQuoteCharEscapeFlags[escapeChar] = true;
|
||||
}
|
||||
foreach (var escapeChar in escapeChars.Union(new[] { '"' }))
|
||||
{
|
||||
DoubleQuoteCharEscapeFlags[escapeChar] = true;
|
||||
}
|
||||
foreach (var escapeChar in escapeChars.Union(new[] { '"', '\'', '<', '>', '&' }))
|
||||
{
|
||||
HtmlCharEscapeFlags[escapeChar] = true;
|
||||
}
|
||||
}
|
||||
|
||||
private const string EscapedUnicodeText = "!";
|
||||
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters)
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling)
|
||||
{
|
||||
// leading delimiter
|
||||
if (appendDelimiters)
|
||||
@@ -53,8 +87,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
var c = s[i];
|
||||
|
||||
// don't escape standard text/numbers except '\' and the text delimiter
|
||||
if (c >= ' ' && c < 128 && c != '\\' && c != delimiter)
|
||||
if (c < charEscapeFlags.Length && !charEscapeFlags[c])
|
||||
continue;
|
||||
|
||||
string escapedValue;
|
||||
@@ -88,24 +121,27 @@ namespace Newtonsoft.Json.Utilities
|
||||
case '\u2029': // Paragraph Separator
|
||||
escapedValue = @"\u2029";
|
||||
break;
|
||||
case '\'':
|
||||
// this charater is being used as the delimiter
|
||||
escapedValue = @"\'";
|
||||
break;
|
||||
case '"':
|
||||
// this charater is being used as the delimiter
|
||||
escapedValue = "\\\"";
|
||||
break;
|
||||
default:
|
||||
if (c <= '\u001f')
|
||||
if (c < charEscapeFlags.Length || stringEscapeHandling == StringEscapeHandling.EscapeNonAscii)
|
||||
{
|
||||
if (unicodeBuffer == null)
|
||||
unicodeBuffer = new char[6];
|
||||
if (c == '\'' && stringEscapeHandling != StringEscapeHandling.EscapeHtml)
|
||||
{
|
||||
escapedValue = @"\'";
|
||||
}
|
||||
else if (c == '"' && stringEscapeHandling != StringEscapeHandling.EscapeHtml)
|
||||
{
|
||||
escapedValue = @"\""";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unicodeBuffer == null)
|
||||
unicodeBuffer = new char[6];
|
||||
|
||||
StringUtils.ToCharAsUnicode(c, unicodeBuffer);
|
||||
StringUtils.ToCharAsUnicode(c, unicodeBuffer);
|
||||
|
||||
// slightly hacky but it saves multiple conditions in if test
|
||||
escapedValue = EscapedUnicodeText;
|
||||
// slightly hacky but it saves multiple conditions in if test
|
||||
escapedValue = EscapedUnicodeText;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,7 +198,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16))
|
||||
{
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters);
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, (delimiter == '"') ? DoubleQuoteCharEscapeFlags : SingleQuoteCharEscapeFlags, StringEscapeHandling.Default);
|
||||
return w.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user