5
votes

I am currently working on a Web API project with a Database-First method using Entity Framework (which I know is not the most stable of platforms yet), but I am running into something very strange.

When the GET method within my APIController tries to return all records in a DbSet with a LINQ Include() method involved such as this, it will return a 500 error:

// GET api/Casinos
    public IEnumerable<casino> Getcasinos()
    {
            var casinos = db.casinos.Include(c => c.city).Include(c => c.state);
            return casinos.AsEnumerable();
        }

Yet, this method works fine, and returns my data from within my database:

// GET api/States
    public IEnumerable<state> Getstates()
    {
        return db.states.AsEnumerable();
    }

So I have proved in other instances that if it returns the entities without LINQ queries, it works great, yet when there is an Include method used upon the DbContext, it fails.

Of course, trying to find this error is impossible, even with Fiddler, Chrome/Firefox dev tools, and adding in GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

If anyone has resolved this, it would be nice to know a nice resolution so I can start returning my data! Thanks!:)

P.S. I am using SQL Server 2012

2
You can create a custom ExceptionFilterAttribute that you can register to see what the error details were. See asp.net/web-api/overview/web-api-routing-and-actions/… for an example. - Oppositional
What you got in fiddler or Chrome, just page 500 error as general? - cuongle
cant you just attach a debugger to get to the root exception? otherwise try/catch round the whole get and then log/throw - Not loved
@CuongLe Yes, I just got a general exception. I fixed it by removing the XML formatter, but I would really hope I wouldn't have to do that, because I would like it to return both JSON and XML, but I guess this is a limitation? - Logan B. Lehman

2 Answers

4
votes

This is happening due to error in serialization (Json/XML). The problem is you are directly trying to transmit your Models over the wire. As an example, see this:

public class Casino
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual City City { get; set; }
}

public class State
{
    public int ID { get; set; }
    public string Name { get; set; }

    [XmlIgnore]
    [IgnoreDataMember]        
    public virtual ICollection<City> Cities { get; set; }
}

public class City
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual  State State { get; set; }

    [XmlIgnore]
    [IgnoreDataMember]
    public virtual ICollection<Casino> Casinos { get; set; }
}

public class Context : DbContext
{
    public Context()
        : base("Casino")
    {

    }

    public DbSet<Casino> Casinos { get; set; }
    public DbSet<State> States { get; set; }
    public DbSet<City> Cities { get; set; }
}

Pay attention to the XmlIgnore and IgnoreDataMember. You need to restrict avoiding serialization so it doesn't happen in circular manner. Further, the above model will still not work because it has virtual. Remove virtual from everywhere namely City, Cities, Casinos and State and then it would work but that would be inefficient.

To sum up: Use DTOs and only send data that you really want to send instead of directly sending your models.

Hope this helps!

1
votes

I had same problem in ASP.Net Core Web Api and made it working with this solution: Add Microsoft.AspNetCore.Mvc.NewtonsoftJson nuget package to web api project. and in Startup.cs class in ConfigureServices method add this code:

services.AddControllersWithViews().AddNewtonsoftJson(options =>
 options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);