Search code examples
c#asp.net-mvcjsonjsonserializer

How to fix a missing child object (navigation property) from JSON serialization from C# controller (OData)?


Stack: MVC5, WebAPI, OData, EF6

In a MVC controller, I am returning an object that is serialized to a JSON object:

                .Select(s => new ProjectEditorDTO()
                {
                    // projection
                    WebsiteId = s.WebsiteId,
                    WebsiteGUID = s.WebsiteGUID,
                    WebsiteName = s.WebsiteName,
                    WebsiteNotes = s.WebsiteNotes,
                    Test = "some test string",
                    DefaultContentType = new ContentTypeDTO 
                        { 
                            ContentTypeId = s.DefaultContentTypeID,
                            Description = s.ContentType.Description
                        }
                });

            var r = results.ToList();  // contains DefaultContentType object

            return Ok(results, results.GetType());

The problem is that when I view the returned data in Fiddler, it's missing the DefaultContentType data inside the JSON object.

I have another controller that uses the same object (alone), and returns just fine.

FYI, here is the ContentTypeDTO:

public class ContentTypeDTO
{
    public int ContentTypeId { get; set; }

    [Required]
    [StringLength(100, MinimumLength=3)]
    [Display(Name="Content Type")]
    public string Description { get; set; }

    //public int NumberOfContentTypes { get; set; }

    //public UserDTO UserDTO { get; set; }
}

I am using WebAPI, and have it configured as the following to return JSON content:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;

        config.Formatters.Remove(config.Formatters.XmlFormatter);

-- UPDATE --

I am using WebAPI and OData, so the resulting call has to contain ProjectEditorDTO object form the ProjectEditor destination:

        modelBuilder.EntitySet<Core.UI.Models.ProjectEditorDTO>("ProjectEditor");              

The data returned from the client is done via an OData URL:

?$format=json&$inlinecount=allpages&$top=10

When I add the $expand= syntax ($format=json&$inlinecount=allpages&$top=10&$expand=DefaultContentTypeID), I get the following error:

Property 'DefaultContentTypeID' on type ... is not a navigation property. Only navigation properties can be expanded.

Even though in the db this is set as a FK.

I'm guessing some expand syntax is missing and ensuring a valid navigation property?

I must be missing something really minor on this... suggestions?


Solution

  • I don't see where the JSON Serialization are. I guess is in the Ok Method. For what I can see, I see that you passed a custom object for treating like a JSON Object. Could yo please try to use a generic object when you project the collection? Just avoiding using your classes to define the objects, something like this:

            .Select(s => new 
            {
                // projection
                WebsiteId = s.WebsiteId,
                WebsiteGUID = s.WebsiteGUID,
                WebsiteName = s.WebsiteName,
                WebsiteNotes = s.WebsiteNotes,
                Test = "some test string",
                DefaultContentType = new 
                    { 
                        ContentTypeId = s.DefaultContentTypeID,
                        Description = s.ContentType.Description
                    }
            });