/// <summary>Writes all the properties of the specified resource or complex object.</summary>
        /// <param name="expanded">Expanded properties for the result.</param>
        /// <param name="customObject">Resource or complex object with properties to write out.</param>
        /// <param name="resourceType">resourceType containing metadata about the current custom object</param>
        /// <param name="absoluteUri">absolute uri for the given resource</param>
        /// <param name="relativeUri">relative uri for the given resource</param>
        /// <param name="item">Item in which to place links / expansions.</param>
        /// <param name="content">Content in which to place values.</param>
        /// <param name="currentSourceRoot">Epm source sub-tree corresponding to <paramref name="customObject"/></param>
        private void WriteObjectProperties(IExpandedResult expanded, object customObject, ResourceType resourceType, Uri absoluteUri, string relativeUri, SyndicationItem item, DictionaryContent content, EpmSourcePathSegment currentSourceRoot)
        {
            Debug.Assert(customObject != null, "customObject != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            Debug.Assert(!String.IsNullOrEmpty(relativeUri), "!String.IsNullOrEmpty(relativeUri)");
            
            if (absoluteUri == null && resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
            {
                // entity type should have an URI, complex type should not have an URI
                // If the static type of the object is "Object", we will mistreat an entity type as complex type and hit this situation
                throw new DataServiceException(500, Strings.BadProvider_InconsistentEntityOrComplexTypeUsage(resourceType.Name));
            }

            this.RecurseEnter();
            try
            {
                List<ResourcePropertyInfo> navProperties = null;
                IEnumerable<ProjectionNode> projectionNodes = null;
                if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                {
                    Debug.Assert(this.CurrentContainer != null, "this.CurrentContainer != null");
                    if (this.Provider.IsEntityTypeDisallowedForSet(this.CurrentContainer, resourceType))
                    {
                        throw new InvalidOperationException(Strings.BaseServiceProvider_NavigationPropertiesOnDerivedEntityTypesNotSupported(resourceType.FullName, this.CurrentContainer.Name));
                    }

                    navProperties = new List<ResourcePropertyInfo>(resourceType.Properties.Count);

                    projectionNodes = this.GetProjections();
                }

                if (projectionNodes == null)
                {
                    var action = resourceType.DictionarySerializerDelegate;
                    if (action == null && this.Provider.IsV1Provider)
                    {
                        Module module = typeof(SyndicationSerializer).Module;
                        Type customObjectType = customObject.GetType();
                        Type[] parameterTypes = new Type[] { typeof(object), typeof(DictionaryContent) };
                        DynamicMethod method = new DynamicMethod("content_populator", typeof(void), parameterTypes, module, false /* skipVisibility */);
                        ILGenerator generator = method.GetILGenerator();
                        MethodInfo methodWritePrimitiveValue = typeof(SyndicationSerializer).GetMethod("WritePrimitiveValue", BindingFlags.Static | BindingFlags.NonPublic);

                        // Downcast the argument.
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Castclass, customObjectType);

                        foreach (ResourceProperty property in resourceType.Properties.Where(p => p.TypeKind == ResourceTypeKind.Primitive))
                        {
                            if (SyndicationSerializer.EpmNeedToSkip(currentSourceRoot, property.Name))
                            {
                                continue;
                            }

                            // WritePrimitiveValue(propertyValue, property.Name, property.ResourceType, content);
                            generator.Emit(OpCodes.Dup);
                            generator.Emit(OpCodes.Call, resourceType.GetPropertyInfo(property).GetGetMethod());
                            if (property.Type.IsValueType)
                            {
                                generator.Emit(OpCodes.Box, property.Type);
                            }

                            generator.Emit(OpCodes.Ldstr, property.Name);
                            generator.Emit(OpCodes.Ldstr, property.ResourceType.FullName);
                            generator.Emit(OpCodes.Ldarg_1);
                            generator.Emit(OpCodes.Call, methodWritePrimitiveValue);
                        }

                        generator.Emit(OpCodes.Pop);
                        generator.Emit(OpCodes.Ret);
                        action = (Action<object, DictionaryContent>)method.CreateDelegate(typeof(Action<object, DictionaryContent>), null);
                        resourceType.DictionarySerializerDelegate = action;
                    }

                    if (action != null)
                    {
                        action(customObject, content);
                    }
                    else
                    {
                        foreach (ResourceProperty property in resourceType.Properties.Where(p => p.TypeKind == ResourceTypeKind.Primitive))
                        {
                            object propertyValue = WebUtil.GetPropertyValue(this.Provider, customObject, resourceType, property, null);
                            if (SyndicationSerializer.EpmNeedToSkip(currentSourceRoot, property.Name))
                            {
                                continue;
                            }

                            WritePrimitiveValue(propertyValue, property.Name, property.ResourceType.FullName, content);
                        }
                    }

                    foreach (ResourceProperty property in this.Provider.GetResourceProperties(this.CurrentContainer, resourceType))
                    {
                        string propertyName = property.Name;
                        if (property.TypeKind == ResourceTypeKind.EntityType)
                        {
                            Debug.Assert(navProperties != null, "navProperties list must be assigned for entity types");

                            object propertyValue =
                                (this.ShouldExpandSegment(property.Name)) ? GetExpandedProperty(this.Provider, expanded, customObject, property) : null;
                            navProperties.Add(new ResourcePropertyInfo(property, propertyValue));
                        }
                        else
                        {
                            if (property.TypeKind == ResourceTypeKind.ComplexType)
                            {
                                object propertyValue = WebUtil.GetPropertyValue(this.Provider, customObject, resourceType, property, null);
                                bool needPop = this.PushSegmentForProperty(property);
                                this.WriteComplexObjectValue(
                                        propertyValue,
                                        propertyName,
                                        property.ResourceType,
                                        relativeUri + "/" + property.Name,
                                        content,
                                        SyndicationSerializer.EpmGetComplexPropertySegment(currentSourceRoot, property.Name));
                                this.PopSegmentName(needPop);
                            }
                        }
                    }

                    if (resourceType.IsOpenType)
                    {
                        IEnumerable<KeyValuePair<string, object>> properties = this.Provider.GetOpenPropertyValues(customObject);
                        foreach (KeyValuePair<string, object> property in properties)
                        {
                            string propertyName = property.Key;

                            if (String.IsNullOrEmpty(propertyName))
                            {
                                throw new DataServiceException(500, Strings.Syndication_InvalidOpenPropertyName(resourceType.FullName));
                            }

                            Type valueType;
                            ResourceType propertyResourceType;

                            object value = property.Value;

                            if (value == null || value == DBNull.Value)
                            {
                                valueType = typeof(string);
                                propertyResourceType = ResourceType.PrimitiveStringResourceType;
                            }
                            else
                            {
                                valueType = value.GetType();
                                propertyResourceType = WebUtil.GetResourceType(this.Provider, value);
                            }

                            // A null ResourceType indicates a ----ed type (eg, IntPtr or DateTimeOffset). So ignore it.
                            if (propertyResourceType == null)
                            {
                                throw new DataServiceException(500, Strings.Syndication_InvalidOpenPropertyType(propertyName));
                            }

                            if (propertyResourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                            {
                                if (value != null && SyndicationSerializer.EpmNeedToSkip(currentSourceRoot, propertyName))
                                {
                                    continue;
                                }

                                WritePrimitiveValue(value, propertyName, propertyResourceType.FullName, content);
                            }
                            else
                            {
                                if (propertyResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                                {
                                    Debug.Assert(propertyResourceType.InstanceType == valueType, "propertyResourceType.Type == valueType");
                                    this.WriteComplexObjectValue(
                                            value,
                                            propertyName,
                                            propertyResourceType,
                                            relativeUri + "/" + propertyName,
                                            content,
                                            SyndicationSerializer.EpmGetComplexPropertySegment(currentSourceRoot, propertyName));
                                }
                                else
                                {
                                    Debug.Assert(
                                        propertyResourceType.ResourceTypeKind == ResourceTypeKind.EntityType,
                                        "propertyResourceType.ResourceTypeKind == ResourceTypeKind.EntityType -- otherwise should have been processed as primitve or complex type.");

                                    // Open navigation properties are not supported on OpenTypes
                                    throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(propertyName));
                                }
                            }
                        }
                    }
                }
                else
                {
                    foreach (ProjectionNode projectionNode in projectionNodes)
                    {
                        string propertyName = projectionNode.PropertyName;
                        ResourceProperty property = resourceType.TryResolvePropertyName(propertyName);

                        // First solve the normal entity type property - turn it into a nav. property record
                        if (property != null && property.TypeKind == ResourceTypeKind.EntityType)
                        {
                            Debug.Assert(navProperties != null, "navProperties list must be assigned for entity types");

                            // By calling the GetResourceProperties we will use the cached list of properties
                            //   for the given type and set. But we have to search through it.
                            // We could use the GetContainer (since that's what the GetResourceProperties does) and check
                            //   if it returns null, but result of that is only partially cached so it might be expensive
                            //   to evaluate for each item in the feed.
                            if (this.Provider.GetResourceProperties(this.CurrentContainer, resourceType).Contains(property))
                            {
                                object expandedPropertyValue =
                                    (this.ShouldExpandSegment(propertyName)) ? GetExpandedProperty(this.Provider, expanded, customObject, property) : null;
                                navProperties.Add(new ResourcePropertyInfo(property, expandedPropertyValue));
                            }

                            continue;
                        }

                        // Now get the property value
                        object propertyValue = WebUtil.GetPropertyValue(this.Provider, customObject, resourceType, property, property == null ? propertyName : null);

                        // Determine the type of the property
                        ResourceType propertyResourceType;
                        if (property != null)
                        {
                            propertyResourceType = property.ResourceType;
                        }
                        else
                        {
                            if (propertyValue == null || propertyValue == DBNull.Value)
                            {
                                propertyResourceType = ResourceType.PrimitiveStringResourceType;
                            }
                            else
                            {
                                propertyResourceType = WebUtil.GetResourceType(this.Provider, propertyValue);

                                // A null ResourceType indicates a ----ed type (eg, IntPtr or DateTimeOffset). So ignore it.
                                if (propertyResourceType == null)
                                {
                                    throw new DataServiceException(500, Strings.Syndication_InvalidOpenPropertyType(propertyName));
                                }
                            }
                        }

                        // And write out the value (depending on the type of the property)
                        if (propertyResourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                        {
                            if (propertyValue == DBNull.Value)
                            {
                                propertyValue = null;
                            }

                            if (propertyValue != null && SyndicationSerializer.EpmNeedToSkip(currentSourceRoot, propertyName))
                            {
                                continue;
                            }

                            WritePrimitiveValue(propertyValue, propertyName, propertyResourceType.FullName, content);
                        }
                        else if (propertyResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            bool needPop = false;
                            if (property != null)
                            {
                                needPop = this.PushSegmentForProperty(property);
                            }

                            this.WriteComplexObjectValue(
                                    propertyValue,
                                    propertyName,
                                    propertyResourceType,
                                    relativeUri + "/" + propertyName,
                                    content,
                                    SyndicationSerializer.EpmGetComplexPropertySegment(currentSourceRoot, propertyName));
                            if (property != null)
                            {
                                this.PopSegmentName(needPop);
                            }
                        }
                        else
                        {
                            Debug.Assert(
                                propertyResourceType.ResourceTypeKind == ResourceTypeKind.EntityType,
                                "propertyResourceType.ResourceTypeKind == ResourceTypeKind.EntityType -- otherwise should have been processed as primitve or complex type.");

                            // Open navigation properties are not supported on OpenTypes
                            throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(propertyName));
                        }
                    }
                }

                if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                {
                    for (int i = 0; i < navProperties.Count; i++)
                    {
                        ResourcePropertyInfo propertyInfo = navProperties[i];
                        ResourceProperty navProperty = propertyInfo.Property;

                        Debug.Assert(
                            navProperty.IsOfKind(ResourcePropertyKind.ResourceReference) ||
                            navProperty.IsOfKind(ResourcePropertyKind.ResourceSetReference),
                            "this must be nav property");

                        // Generate a link - see http://tools.ietf.org/html/rfc4287#section-4.2.7
                        string linkType = navProperty.IsOfKind(ResourcePropertyKind.ResourceReference) ? XmlConstants.AtomEntryElementName : XmlConstants.AtomFeedElementName;
                        linkType = String.Format(CultureInfo.InvariantCulture, "{0};{1}={2}", XmlConstants.MimeApplicationAtom, XmlConstants.AtomTypeAttributeName, linkType);
                        string segmentIdentifier = navProperty.Name;

                        if (!this.ShouldExpandSegment(navProperty.Name))
                        {
                            WriteDeferredContentElement(
                                XmlConstants.DataWebRelatedNamespace + navProperty.Name,
                                navProperty.Name,
                                relativeUri + "/" + segmentIdentifier,
                                linkType,
                                item);
                        }
                        else
                        {
                            object propertyValue = propertyInfo.Value;
                            IExpandedResult expandedResultPropertyValue = propertyValue as IExpandedResult;
                            object expandedPropertyValue =
                                expandedResultPropertyValue != null ?
                                GetExpandedElement(expandedResultPropertyValue) :
                                propertyValue;
                            string propertyRelativeUri = relativeUri + "/" + segmentIdentifier;
                            Uri propertyAbsoluteUri = RequestUriProcessor.AppendUnescapedSegment(absoluteUri, segmentIdentifier);

                            SyndicationLink link = new SyndicationLink();
                            link.RelationshipType = XmlConstants.DataWebRelatedNamespace + navProperty.Name;
                            link.Title = navProperty.Name;
                            link.Uri = new Uri(propertyRelativeUri, UriKind.RelativeOrAbsolute);
                            link.MediaType = linkType;
                            item.Links.Add(link);

                            bool needPop = this.PushSegmentForProperty(navProperty);

                            // if this.CurrentContainer is null, the target set of the navigation property is hidden.
                            if (this.CurrentContainer != null)
                            {
                                if (navProperty.IsOfKind(ResourcePropertyKind.ResourceSetReference))
                                {
                                    IEnumerable enumerable;
                                    bool collection = WebUtil.IsElementIEnumerable(expandedPropertyValue, out enumerable);
                                    Debug.Assert(collection, "metadata loading must have ensured that navigation set properties must implement IEnumerable");

                                    SyndicationFeed feed = new SyndicationFeed();
                                    InlineAtomFeed inlineFeedExtension = new InlineAtomFeed(feed, this.factory);
                                    link.ElementExtensions.Add(inlineFeedExtension);
                                    IEnumerator enumerator = enumerable.GetEnumerator();
                                    try
                                    {
                                        bool hasMoved = enumerator.MoveNext();
                                        this.WriteFeedElements(
                                            propertyValue as IExpandedResult, 
                                            enumerator, 
                                            navProperty.ResourceType, 
                                            navProperty.Name, 
                                            propertyAbsoluteUri, 
                                            propertyRelativeUri, 
                                            hasMoved, 
                                            feed,
                                            true);
                                    }
                                    catch
                                    {
                                        WebUtil.Dispose(enumerator);
                                        throw;
                                    }
                                }
                                else
                                {
                                    SyndicationItem inlineItem = new SyndicationItem();
                                    this.WriteEntryElement(propertyValue as IExpandedResult, expandedPropertyValue, navProperty.ResourceType, propertyAbsoluteUri, propertyRelativeUri, inlineItem);
                                    InlineAtomItem inlineItemExtension = new InlineAtomItem(inlineItem, this.factory);
                                    link.ElementExtensions.Add(inlineItemExtension);
                                }
                            }

                            this.PopSegmentName(needPop);
                        }
                    }
                }
            }
            finally
            {
                // The matching call to RecurseLeave is in a try/finally block not because it's necessary in the 
                // presence of an exception (progress will halt anyway), but because it's easier to maintain in the 
                // code in the presence of multiple exit points (returns).
                this.RecurseLeave();
            }
        }
        /// <summary>
        /// Creates an expression to access a property.
        /// </summary>
        /// <param name="source">The source expression which evaluates to the instance to access the property on.</param>
        /// <param name="sourceResourceType">The resource type of the source expression.</param>
        /// <param name="resourceProperty">The resource property to access.</param>
        /// <returns>An expression which evaluates to the property value.</returns>
        private static Expression CreatePropertyAccessExpression(Expression source, ResourceType sourceResourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(source != null, "source != null");
            Debug.Assert(sourceResourceType != null, "sourceResourceType != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
            Debug.Assert(sourceResourceType.Properties.Contains(resourceProperty), "resourceProperty is not declared on sourceResourceType");
#if DEBUG
            Debug.Assert(TypeUtils.AreTypesEquivalent(source.Type, sourceResourceType.InstanceType), "source.Type != sourceResourceType.InstanceType");
#endif

            // TODO: Deal with null propagation???
            if (resourceProperty.CanReflectOnInstanceTypeProperty)
            {
                return Expression.Property(source, sourceResourceType.GetPropertyInfo(resourceProperty));
            }
            else
            {
                // TODO: Support for untyped and open properties
                throw new NotImplementedException();
            }
        }