protected bool IsErrorHandled(object currentObject, JsonContract contract, object keyValue, Exception ex)
        {
            ErrorContext errorContext = GetErrorContext(currentObject, keyValue, ex);
              contract.InvokeOnError(currentObject, Serializer.Context, errorContext);

              if (!errorContext.Handled)
            Serializer.OnError(new ErrorEventArgs(currentObject, errorContext));

              return errorContext.Handled;
        }
        private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract)
        {
            if (value == null)
            return false;
              if (contract is JsonPrimitiveContract)
            return false;

              bool? isReference = null;

              // value could be coming from a dictionary or array and not have a property
              if (property != null)
            isReference = property.IsReference;

              if (isReference == null)
            isReference = contract.IsReference;

              if (isReference == null)
              {
            if (contract is JsonArrayContract)
              isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
            else
              isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
              }

              if (!isReference.Value)
            return false;

              return Serializer.ReferenceResolver.IsReferenced(value);
        }
        private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContract collectionValueContract)
        {
            JsonConverter converter = (member != null) ? member.Converter : null;

              if (value == null)
              {
            writer.WriteNull();
            return;
              }

              if ((converter != null
              || ((converter = valueContract.Converter) != null)
              || ((converter = Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null)
              || ((converter = valueContract.InternalConverter) != null))
            && converter.CanWrite)
              {
            SerializeConvertable(writer, converter, value, valueContract);
              }
              else if (valueContract is JsonPrimitiveContract)
              {
            writer.WriteValue(value);
              }
              else if (valueContract is JsonStringContract)
              {
            SerializeString(writer, value, (JsonStringContract) valueContract);
              }
              else if (valueContract is JsonObjectContract)
              {
            SerializeObject(writer, value, (JsonObjectContract)valueContract, member, collectionValueContract);
              }
              else if (valueContract is JsonDictionaryContract)
              {
            JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) valueContract;
            SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, collectionValueContract);
              }
              else if (valueContract is JsonArrayContract)
              {
            if (value is IList)
            {
              SerializeList(writer, (IList)value, (JsonArrayContract)valueContract, member, collectionValueContract);
            }
            else if (value is IEnumerable)
            {
              SerializeList(writer, ((IEnumerable)value).Cast<object>().ToList(), (JsonArrayContract)valueContract, member, collectionValueContract);
            }
            else
            {
              throw new Exception(
            "Cannot serialize '{0}' into a JSON array. Type does not implement IEnumerable.".FormatWith(
              CultureInfo.InvariantCulture, value.GetType()));
            }
              }
              else if (valueContract is JsonLinqContract)
              {
            ((JToken)value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
              }
            #if !SILVERLIGHT && !PocketPC
              else if (valueContract is JsonISerializableContract)
              {
            SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) valueContract);
              }
            #endif
        }
        private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContract collectionValueContract)
        {
            contract.InvokeOnSerializing(value, Serializer.Context);

              SerializeStack.Add(value);
              writer.WriteStartObject();

              bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
              if (isReference)
              {
            writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
            writer.WriteValue(Serializer.ReferenceResolver.GetReference(value));
              }
              if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract))
              {
            WriteTypeProperty(writer, contract.UnderlyingType);
              }

              int initialDepth = writer.Top;

              foreach (JsonProperty property in contract.Properties)
              {
            try
            {
              if (!property.Ignored && property.Readable && ShouldSerialize(property, value))
              {
            object memberValue = property.ValueProvider.GetValue(value);
            JsonContract memberContract = GetContractSafe(memberValue);

            WriteMemberInfoProperty(writer, memberValue, property, memberContract);
              }
            }
            catch (Exception ex)
            {
              if (IsErrorHandled(value, contract, property.PropertyName, ex))
            HandleError(writer, initialDepth);
              else
            throw;
            }
              }

              writer.WriteEndObject();
              SerializeStack.RemoveAt(SerializeStack.Count - 1);

              contract.InvokeOnSerialized(value, Serializer.Context);
        }
        private void SerializeList(JsonWriter writer, IList values, JsonArrayContract contract, JsonProperty member, JsonContract collectionValueContract)
        {
            contract.InvokeOnSerializing(values, Serializer.Context);

              SerializeStack.Add(values);

              bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
              bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, collectionValueContract);

              if (isReference || includeTypeDetails)
              {
            writer.WriteStartObject();

            if (isReference)
            {
              writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
              writer.WriteValue(Serializer.ReferenceResolver.GetReference(values));
            }
            if (includeTypeDetails)
            {
              WriteTypeProperty(writer, values.GetType());
            }
            writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName);
              }

              JsonContract childValuesContract = Serializer.ContractResolver.ResolveContract(contract.CollectionItemType ?? typeof(object));

              writer.WriteStartArray();

              int initialDepth = writer.Top;

              for (int i = 0; i < values.Count; i++)
              {
            try
            {
              object value = values[i];
              JsonContract valueContract = GetContractSafe(value);

              if (ShouldWriteReference(value, null, valueContract))
              {
            WriteReference(writer, value);
              }
              else
              {
            if (!CheckForCircularReference(value, null, contract))
              continue;

            SerializeValue(writer, value, valueContract, null, childValuesContract);
              }
            }
            catch (Exception ex)
            {
              if (IsErrorHandled(values, contract, i, ex))
            HandleError(writer, initialDepth);
              else
            throw;
            }
              }

              writer.WriteEndArray();

              if (isReference || includeTypeDetails)
              {
            writer.WriteEndObject();
              }

              SerializeStack.RemoveAt(SerializeStack.Count - 1);

              contract.InvokeOnSerialized(values, Serializer.Context);
        }
        private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContract collectionValueContract)
        {
            contract.InvokeOnSerializing(values.UnderlyingDictionary, Serializer.Context);

              SerializeStack.Add(values.UnderlyingDictionary);
              writer.WriteStartObject();

              bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
              if (isReference)
              {
            writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
            writer.WriteValue(Serializer.ReferenceResolver.GetReference(values.UnderlyingDictionary));
              }
              if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract))
              {
            WriteTypeProperty(writer, values.UnderlyingDictionary.GetType());
              }

              JsonContract childValuesContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object));

              int initialDepth = writer.Top;

              // Mono Unity 3.0 fix
              IDictionary d = values;

              foreach (DictionaryEntry entry in d)
              {
            string propertyName = GetPropertyName(entry);

            try
            {
              object value = entry.Value;
              JsonContract valueContract = GetContractSafe(value);

              if (ShouldWriteReference(value, null, valueContract))
              {
            writer.WritePropertyName(propertyName);
            WriteReference(writer, value);
              }
              else
              {
            if (!CheckForCircularReference(value, null, contract))
              continue;

            writer.WritePropertyName(propertyName);

            SerializeValue(writer, value, valueContract, null, childValuesContract);
              }
            }
            catch (Exception ex)
            {
              if (IsErrorHandled(values.UnderlyingDictionary, contract, propertyName, ex))
            HandleError(writer, initialDepth);
              else
            throw;
            }
              }

              writer.WriteEndObject();
              SerializeStack.RemoveAt(SerializeStack.Count - 1);

              contract.InvokeOnSerialized(values.UnderlyingDictionary, Serializer.Context);
        }
        private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract)
        {
            if (ShouldWriteReference(value, null, contract))
              {
            WriteReference(writer, value);
              }
              else
              {
            if (!CheckForCircularReference(value, null, contract))
              return;

            SerializeStack.Add(value);

            converter.WriteJson(writer, value, GetInternalSerializer());

            SerializeStack.RemoveAt(SerializeStack.Count - 1);
              }
        }
        private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string reference)
        {
            object value;
              if (HasDefinedType(objectType))
              {
            JsonArrayContract arrayContract = EnsureArrayContract(objectType, contract);

            if (existingValue == null)
              value = CreateAndPopulateList(reader, reference, arrayContract);
            else
              value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, reference, arrayContract);
              }
              else
              {
            value = CreateJToken(reader, contract);
              }
              return value;
        }
        private JsonArrayContract EnsureArrayContract(Type objectType, JsonContract contract)
        {
            if (contract == null)
            throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));

              JsonArrayContract arrayContract = contract as JsonArrayContract;
              if (arrayContract == null)
            throw new JsonSerializationException("Cannot deserialize JSON array into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));

              return arrayContract;
        }
 private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter)
 {
     JsonConverter converter = null;
       if (memberConverter != null)
       {
     // member attribute converter
     converter = memberConverter;
       }
       else if (contract != null)
       {
     JsonConverter matchingConverter;
     if (contract.Converter != null)
       // class attribute converter
       converter = contract.Converter;
     else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
       // passed in converters
       converter = matchingConverter;
     else if (contract.InternalConverter != null)
       // internally specified converter
       converter = contract.InternalConverter;
       }
       return converter;
 }
        private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract)
        {
            JsonConverter converter = GetConverter(contract, null);

              if (converter != null && converter.CanRead)
            return converter.ReadJson(reader, objectType, null, GetInternalSerializer());

              return CreateValueInternal(reader, objectType, contract, null, null);
        }
        private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue)
        {
            if (contract is JsonLinqContract)
            return CreateJToken(reader, contract);

              do
              {
            switch (reader.TokenType)
            {
              // populate a typed object or generic dictionary/array
              // depending upon whether an objectType was supplied
              case JsonToken.StartObject:
            return CreateObject(reader, objectType, contract, member, existingValue);
              case JsonToken.StartArray:
            return CreateList(reader, objectType, contract, member, existingValue, null);
              case JsonToken.Integer:
              case JsonToken.Float:
              case JsonToken.Boolean:
              case JsonToken.Date:
              case JsonToken.Bytes:
            return EnsureType(reader.Value, objectType);
              case JsonToken.String:
            // convert empty string to null automatically for nullable types
            if (string.IsNullOrEmpty((string)reader.Value) &&
              objectType != null &&
              ReflectionUtils.IsNullableType(objectType))
              return null;

            // string that needs to be returned as a byte array should be base 64 decoded
            if (objectType == typeof(byte[]))
              return Convert.FromBase64String((string)reader.Value);

            return EnsureType(reader.Value, objectType);
              case JsonToken.StartConstructor:
              case JsonToken.EndConstructor:
            string constructorName = reader.Value.ToString();

            return constructorName;
              case JsonToken.Null:
              case JsonToken.Undefined:
            if (objectType == typeof (DBNull))
              return DBNull.Value;

            return EnsureType(reader.Value, objectType);
              case JsonToken.Raw:
            return new JRaw((string)reader.Value);
              case JsonToken.Comment:
            // ignore
            break;
              default:
            throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
            }
              } while (reader.Read());

              throw new JsonSerializationException("Unexpected end when deserializing object.");
        }
        private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue)
        {
            CheckedRead(reader);

              string id = null;

              if (reader.TokenType == JsonToken.PropertyName)
              {
            bool specialProperty;

            do
            {
              string propertyName = reader.Value.ToString();

              if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
              {
            CheckedRead(reader);
            if (reader.TokenType != JsonToken.String)
              throw new JsonSerializationException("JSON reference {0} property must have a string value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));

            string reference = reader.Value.ToString();

            CheckedRead(reader);
            if (reader.TokenType == JsonToken.PropertyName)
              throw new JsonSerializationException("Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));

            return Serializer.ReferenceResolver.ResolveReference(reference);
              }
              else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
              {
            CheckedRead(reader);
            string qualifiedTypeName = reader.Value.ToString();

            CheckedRead(reader);

            if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) != TypeNameHandling.None)
            {
              string typeName;
              string assemblyName;
              ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);

              Type specifiedType;
              try
              {
                specifiedType = Serializer.Binder.BindToType(assemblyName, typeName);
              }
              catch (Exception ex)
              {
                throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
              }

              if (specifiedType == null)
                throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));

              if (objectType != null && !objectType.IsAssignableFrom(specifiedType))
                throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));

              objectType = specifiedType;
              contract = GetContractSafe(specifiedType);
            }
            specialProperty = true;
              }
              else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
              {
            CheckedRead(reader);

            id = reader.Value.ToString();
            CheckedRead(reader);
            specialProperty = true;
              }
              else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
              {
            CheckedRead(reader);
            object list = CreateList(reader, objectType, contract, member, existingValue, id);
            CheckedRead(reader);
            return list;
              }
              else
              {
            specialProperty = false;
              }
            } while (specialProperty
                 && reader.TokenType == JsonToken.PropertyName);
              }

              if (!HasDefinedType(objectType))
            return CreateJObject(reader);

              if (contract == null)
            throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));

              JsonDictionaryContract dictionaryContract = contract as JsonDictionaryContract;
              if (dictionaryContract != null)
              {
            if (existingValue == null)
              return CreateAndPopulateDictionary(reader, dictionaryContract, id);

            return PopulateDictionary(dictionaryContract.CreateWrapper(existingValue), reader, dictionaryContract, id);
              }

              JsonObjectContract objectContract = contract as JsonObjectContract;
              if (objectContract != null)
              {
            if (existingValue == null)
              return CreateAndPopulateObject(reader, objectContract, id);

            return PopulateObject(existingValue, reader, objectContract, id);
              }

            #if !SILVERLIGHT && !PocketPC
              JsonISerializableContract serializableContract = contract as JsonISerializableContract;
              if (serializableContract != null)
              {
            return CreateISerializable(reader, serializableContract, id);
              }
            #endif

              throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
        }
        //private bool ShouldWriteTypeProperty(JsonProperty member, JsonContract contract, TypeNameHandling typeFlag)
        //{
        //  if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, typeFlag))
        //    return true;
        //  if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) == TypeNameHandling.Auto)
        //      || (member != null
        //          && (member.TypeNameHandling ?? Serializer.TypeNameHandling) == TypeNameHandling.Auto
        //          && contract.UnderlyingType != member.PropertyType)
        //      )
        //}
        private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContract collectionValueContract)
        {
            if (HasFlag(((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling, typeNameHandlingFlag))
            return true;

              if (member != null)
              {
            if ((member.TypeNameHandling ?? Serializer.TypeNameHandling) == TypeNameHandling.Auto && contract.UnderlyingType != member.PropertyType)
              return true;
              }
              else if (collectionValueContract != null)
              {
            if (Serializer.TypeNameHandling == TypeNameHandling.Auto && contract.UnderlyingType != collectionValueContract.UnderlyingType)
              return true;
              }

              return false;
        }
        private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling, JsonContract contract)
        {
            if (value == null || contract is JsonPrimitiveContract)
            return true;

              if (SerializeStack.IndexOf(value) != -1)
              {
            switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling))
            {
              case ReferenceLoopHandling.Error:
            throw new JsonSerializationException("Self referencing loop");
              case ReferenceLoopHandling.Ignore:
            return false;
              case ReferenceLoopHandling.Serialize:
            return true;
              default:
            throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, Serializer.ReferenceLoopHandling));
            }
              }

              return true;
        }
        private void WriteMemberInfoProperty(JsonWriter writer, object memberValue, JsonProperty property, JsonContract contract)
        {
            string propertyName = property.PropertyName;
              object defaultValue = property.DefaultValue;

              if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore &&
              memberValue == null)
            return;

              if (property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling) ==
              DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
            return;

              if (ShouldWriteReference(memberValue, property, contract))
              {
            writer.WritePropertyName(propertyName);
            WriteReference(writer, memberValue);
            return;
              }

              if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling, contract))
            return;

              if (memberValue == null && property.Required == Required.Always)
            throw new JsonSerializationException("Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));

              writer.WritePropertyName(propertyName);
              SerializeValue(writer, memberValue, contract, property, null);
        }
        private JToken CreateJToken(JsonReader reader, JsonContract contract)
        {
            ValidationUtils.ArgumentNotNull(reader, "reader");

              if (contract != null && contract.UnderlyingType == typeof(JRaw))
              {
            return JRaw.Create(reader);
              }
              else
              {
            JToken token;
            using (JTokenWriter writer = new JTokenWriter())
            {
              writer.WriteToken(reader);
              token = writer.Token;
            }

            return token;
              }
        }