简体   繁体   中英

Dealing with Object Graphs - Web API

I recently encountered a (hopefully) small issue when toying around with a Web API project that involves returning object graphs so that they can be read as JSON.

Example of Task Object (generated through EF) :

//A Task Object (Parent) can consist of many Activities (Child Objects)
public partial class Task
{
    public Task()
    {
        this.Activities = new HashSet<Activity>();
    }

    public int TaskId { get; set; }
    public string TaskSummary { get; set; }
    public string TaskDetail { get; set; }

    public virtual ICollection<Activity> Activities { get; set; }
}

within my ApiController, I am requested a specific Task (by Id) along with all of it's associated Activities, via:

Example of Single Task Request

//Simple example of pulling an object along with the associated activities.
return repository.Single(t => t.Id == id).Include("Activities");  

Everything appears to be working fine - however when I attempt to navigate to a URL to access this, such as /api/tasks/1 , the method executes as it should, but no object is returned (just a simple cannot find that page).

If I request an Task that contains no activities - everything works as expected and it returns the proper JSON object with Activities : [] .

I'm sure there are many way to tackle this issue - I just thought I would get some insight as to what people consider the best method of handling this.

Considered Methods (so far):

  • Using an alternative JSON Parser (such as Newtonsoft.JSON) which fixed the issue but appended $id and $refs throughout the return data, which could make parsing for Knockout difficult I believe.

  • Using projection and leveraging anonymous types to return the data. (Untested so far)

  • Removing the Include entirely and simply accessing the Child Data through another request.

Any and all suggestions would be greatly appreciated.

I had a similar issue with EF types and Web API recently. Depending on how your generated EF models are setup, the navigation properties may result in circular dependencies. So if your generated Activity class has a Task reference the serializer will try to walk the object graph and get thrown in a little nasty cycle.

One solution would be to create a simple view model to get the serializer working

public class TaskViewModel {
  public TaskViewModel ()
  {
     this.Activities = new List<ActivityViewModel>();
   }

  public int TaskId { get; set; }
  public string TaskSummary { get; set; }
  public string TaskDetail { get; set; }

  public virtual IList<ActivityViewModel> Activities { get; set; }
}

public class ActivityViewModel{
  public ActivityViewModel()
  {        
  }

  //Activity stuff goes here
  //No reference to Tasks here!!
}

Depending on what you're doing, you may even be able to create a flatter model than this but removing the Task reference will help the serialization. That's probably why it worked when Activities was empty

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM