protected void WriteFullObjectJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var valueType = value.GetType();
            var contract  = (JsonObjectContract)serializer.ContractResolver.ResolveContract(valueType);

            writer.WriteStartObject();

            //will capture id and type as we go through
            object id   = null;
            object type = null;

            //A resource object MUST contain at least the following top-level members: type
            var typeProp = contract.Properties.GetClosestMatchProperty("type");

            if (typeProp == null)
            {
                writer.WritePropertyName("type");
                type = GenerateDefaultTypeName(valueType);
                serializer.Serialize(writer, GenerateDefaultTypeName(valueType));
            }

            List <JsonWriterCapture> attributes    = new List <JsonWriterCapture>();
            List <JsonWriterCapture> relationships = new List <JsonWriterCapture>();

            foreach (var prop in contract.Properties.Where(x => !x.Ignored))
            {
                var propValue = prop.ValueProvider.GetValue(value);
                if (propValue == null && serializer.NullValueHandling == NullValueHandling.Ignore)
                {
                    continue;
                }

                switch (prop.PropertyName)
                {
                //In addition, a resource object MAY contain any of these top - level members: links, meta, attributes, relationships
                case PropertyNames.Id:     //Id is optional on base objects
                    id = propValue;
                    writer.WritePropertyName(prop.PropertyName);
                    serializer.Serialize(writer, id);
                    break;

                case PropertyNames.Links:
                case PropertyNames.Meta:
                    writer.WritePropertyName(prop.PropertyName);
                    serializer.Serialize(writer, propValue);
                    break;

                case PropertyNames.Type:
                    writer.WritePropertyName("type");
                    type = typeProp?.ValueProvider?.GetValue(value) ?? GenerateDefaultTypeName(valueType);
                    serializer.Serialize(writer, type);
                    break;

                default:
                    //we do not know if it is an Attribute or a Relationship
                    //so we will send out a probe to determine which one it is
                    var probe = new AttributeOrRelationshipProbe();
                    probe.WritePropertyName(prop.PropertyName);
                    serializer.Serialize(probe, propValue);

                    (probe.PropertyType == AttributeOrRelationshipProbe.Type.Attribute
                            ? attributes
                            : relationships).Add(probe);
                    break;
                }
            }

            //add reference to this type, so others can reference it
            var referenceValue = IncludedReferenceResolver.GetReferenceValue(id?.ToString(), type?.ToString());

            serializer.ReferenceResolver.AddReference(null, referenceValue, value);

            //output our attibutes in an attribute tag
            if (attributes.Count > 0)
            {
                writer.WritePropertyName(PropertyNames.Attributes);
                writer.WriteStartObject();
                foreach (var attribute in attributes)
                {
                    attribute.ApplyCaptured(writer);
                }
                writer.WriteEndObject();
            }

            //output our relationships in a relationship tag
            if (relationships.Count > 0)
            {
                writer.WritePropertyName(PropertyNames.Relationships);
                writer.WriteStartObject();
                foreach (var relationship in relationships)
                {
                    relationship.ApplyCaptured(writer);
                }
                writer.WriteEndObject();
            }

            writer.WriteEndObject();
        }
        protected void WriteReferenceObjectJson(JsonWriter writer, object value, JsonSerializer serializer, JsonObjectContract contract = null)
        {
            contract = contract ?? (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());

            writer.WriteStartObject();

            //A "resource identifier object" MUST contain type and id members.
            writer.WritePropertyName(PropertyNames.Id);
            var idProp = contract.Properties.GetClosestMatchProperty(PropertyNames.Id);
            var idVal  = idProp?.ValueProvider?.GetValue(value) ?? string.Empty;

            serializer.Serialize(writer, idVal);

            writer.WritePropertyName(PropertyNames.Type);
            var typeProp = contract.Properties.GetClosestMatchProperty(PropertyNames.Type);
            var typeVal  = typeProp?.ValueProvider?.GetValue(value) ?? GenerateDefaultTypeName(value.GetType());

            serializer.Serialize(writer, typeVal);

            //we will only write the object to included if there are properties that have have data
            //that we cant include within the reference
            var willWriteObjectToIncluded = contract.Properties.Any(prop =>
            {
                //ignore id, type, meta and ignored properties
                if (prop.PropertyName == PropertyNames.Id ||
                    prop.PropertyName == PropertyNames.Type ||
                    prop.PropertyName == PropertyNames.Meta ||
                    prop.Ignored)
                {
                    return(false);
                }

                //ignore null properties
                var propValue = prop.ValueProvider.GetValue(value);
                if (propValue == null && serializer.NullValueHandling == NullValueHandling.Ignore)
                {
                    return(false);
                }

                //we have another property with a value
                return(true);
            });

            //typeically we would just write the meta in the included. But if we are not going to
            //have something in included we will write the meta inline here
            if (!willWriteObjectToIncluded)
            {
                var metaProp = contract.Properties.GetClosestMatchProperty(PropertyNames.Meta);
                var metaVal  = metaProp?.ValueProvider?.GetValue(value);
                if (metaVal != null)
                {
                    writer.WritePropertyName(PropertyNames.Meta);
                    serializer.Serialize(writer, metaVal);
                }
            }


            writer.WriteEndObject();


            if (willWriteObjectToIncluded)
            {
                var reference = IncludedReferenceResolver.GetReferenceValue(idVal.ToString(), typeVal.ToString());
                serializer.ReferenceResolver.AddReference(null, reference, value);
            }
        }
Ejemplo n.º 3
0
        private void WriteResourceJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var resolver     = (serializer.ReferenceResolver as IncludedReferenceResolver);
            var currentIndex = resolver.RefList.Count;
            var valueType    = value.GetType();

            //Serialize object
            var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(valueType);

            writer.WriteStartObject();

            //will capture id and type as we go through
            object id   = null;
            object type = null;

            //Handle link
            var linkProps = valueType.GetProperties().Where(p => p.GetCustomAttributes(typeof(ResourceAttribute), false).Count() != 0).ToList();

            //A resource object MUST contain at least the following top-level members: type
            var typeProp = contract.Properties.GetClosestMatchProperty("type");

            type = GenerateDefaultTypeName(valueType);
            if (typeProp == null)
            {
                writer.WritePropertyName("type");
                serializer.Serialize(writer, type);
            }

            List <JsonWriterCapture> attributes    = new List <JsonWriterCapture>();
            List <JsonWriterCapture> relationships = new List <JsonWriterCapture>();

            foreach (var prop in contract.Properties.Where(x => !x.Ignored))
            {
                var propValue = prop.ValueProvider.GetValue(value);
                if (propValue == null && (prop.NullValueHandling ?? serializer.NullValueHandling) == NullValueHandling.Ignore)
                {
                    continue;
                }

                switch (prop.PropertyName)
                {
                //In addition, a resource object MAY contain any of these top - level members: links, meta, attributes, relationships
                case PropertyNames.Id:     //Id is optional on base objects
                case PropertyNames.Tid:    //
                    id = propValue;
                    writer.WritePropertyName(prop.PropertyName);
                    serializer.Serialize(writer, id);
                    break;

                case PropertyNames.Meta:
                    writer.WritePropertyName(prop.PropertyName);
                    serializer.Serialize(writer, propValue);
                    break;

                case PropertyNames.Type:
                    writer.WritePropertyName(PropertyNames.Type);
                    type = typeProp?.ValueProvider?.GetValue(value) ?? GenerateDefaultTypeName(valueType);
                    serializer.Serialize(writer, type);
                    break;

                default:
                    var resAttr = linkProps?.Where(l => l.Name.ToLower() == prop.PropertyName.ToLower()).SingleOrDefault();

                    //we do not know if it is an Attribute or a Relationship
                    //so we will send out a probe to determine which one it is
                    var probe = new AttributeOrRelationshipProbe();
                    probe.WritePropertyName(prop.PropertyName);
                    serializer.Serialize(probe, propValue);

                    //handle relationship links start
                    if (probe.PropertyType == AttributeOrRelationshipProbe.Type.Relationship)
                    {
                        ResourceAttribute link = null;
                        if (resAttr != null)
                        {
                            link = resAttr.GetCustomAttributes(typeof(ResourceAttribute), false)[0] as ResourceAttribute;
                            if (link.Links != null && link.Links.Count > 0)
                            {
                                //probe.WriteStartObject();
                                var act = probe.GetActions();
                                //001:remove last entry and add links
                                act.RemoveAt(act.Count - 1);

                                WriterUtil.GenerateResourceLinks(serializer, probe, value, link, type.ToString(), prop.PropertyName, propValue);
                                //additional end object since it is removed to add links in 001 section
                                probe.AddEndObject();
                            }
                            if (!link.IsResource)
                            {
                                probe.PropertyType = AttributeOrRelationshipProbe.Type.Attribute;
                            }
                        }

                        //Handle Includes
                        if (resolver.Includes != null && resolver.Includes.Count() > 0)
                        {
                            if (ListUtil.IsList(propValue.GetType()))
                            {
                                var enumerable   = propValue as IEnumerable <object> ?? Enumerable.Empty <object>();
                                var include_name = ((link != null && !string.IsNullOrEmpty(link.IncludeName)) ? link.IncludeName : prop.PropertyName);
                                if (enumerable.Count() > 0 && resolver.Includes.Contains(include_name.ToLower()))
                                {
                                    foreach (var valueElement in enumerable)
                                    {
                                        var include_id   = valueElement.GetType().GetProperties().Where(p => p.Name.ToLower() == PropertyNames.Id).FirstOrDefault()?.GetValue(valueElement);
                                        var include_type = valueElement.GetType().GetProperties().Where(p => p.Name.ToLower() == PropertyNames.Type).FirstOrDefault()?.GetValue(valueElement);
                                        if (include_type == null)
                                        {
                                            include_type = valueElement.GetType().Name.ToLower();
                                        }
                                        if (include_id != null && include_type != null)
                                        {
                                            var refer = IncludedReferenceResolver.GetReferenceValue(include_id.ToString(), include_type.ToString());
                                            resolver.ResourceToInclude.Add(refer);
                                            serializer.ReferenceResolver.AddReference(null, refer, valueElement);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                var include_id   = propValue.GetType().GetProperties().Where(p => p.Name.ToLower() == PropertyNames.Id).FirstOrDefault()?.GetValue(propValue);
                                var include_type = propValue.GetType().GetProperties().Where(p => p.Name.ToLower() == PropertyNames.Type).FirstOrDefault()?.GetValue(propValue);
                                if (include_type == null)
                                {
                                    include_type = propValue.GetType().Name.ToLower();
                                }
                                if (include_id != null && include_type != null)
                                {
                                    var include_name = ((link != null && !string.IsNullOrEmpty(link.IncludeName)) ? link.IncludeName : prop.PropertyName);
                                    if (resolver.Includes != null && resolver.Includes.Contains(include_name.ToLower()))
                                    {
                                        var refer = IncludedReferenceResolver.GetReferenceValue(include_id.ToString(), include_type.ToString());
                                        resolver.ResourceToInclude.Add(refer);
                                        serializer.ReferenceResolver.AddReference(null, refer, propValue);
                                    }
                                }
                            }
                        }
                    }
                    //handle relationship links end

                    (probe.PropertyType == AttributeOrRelationshipProbe.Type.Attribute
                                   ? attributes
                                   : relationships).Add(probe);

                    break;
                }
            }

            //add reference to this type, so others can reference it
            var referenceValue = IncludedReferenceResolver.GetReferenceValue(id?.ToString(), type?.ToString());

            serializer.ReferenceResolver.AddReference(null, referenceValue, value);
            resolver?.RenderedReferences?.Add(referenceValue);

            //set parent reference for generating link parameters
            for (int i = currentIndex; i < resolver.RefList.Count; i++)
            {
                if (resolver.RefList[i].Reference != referenceValue)
                {
                    resolver.RefList[i].ParentReference = referenceValue;
                }
            }
            //output our attibutes in an attribute tag
            if (attributes.Count > 0)
            {
                writer.WritePropertyName(PropertyNames.Attributes);
                writer.WriteStartObject();
                foreach (var attribute in attributes)
                {
                    attribute.ApplyCaptured(writer);
                }
                writer.WriteEndObject();
            }

            //output our relationships in a relationship tag
            if (relationships.Count > 0)
            {
                writer.WritePropertyName(PropertyNames.Relationships);
                writer.WriteStartObject();

                foreach (var relationship in relationships)
                {
                    relationship.ApplyCaptured(writer);
                }
                writer.WriteEndObject();
            }
            //Links
            var res = ((value.GetType().GetCustomAttributes(typeof(ResourceAttribute))).SingleOrDefault() as ResourceAttribute);

            WriterUtil.GenerateResourceLinks(serializer, writer, value, res, type.ToString());

            writer.WriteEndObject();
        }