سؤال

I'm trying to use a web API method, but I'm not having much success.

In my Controller I have:

public class TestAPIController : ApiController
{
public string Get()
    {
        return "Hello World";
    }

    public Cours Get(int id)
    {
        using (SSDEntities Entity = new SSDEntities())
        return Entity.Courses.SingleOrDefault<Cours>(a => a.ID == id);
    }

In my Global.asax I have:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
    );
        routes.MapHttpRoute(
            name: "ApiWithAction",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}", // URL with parameters
            new { controller = "Home", action = "Index" } // Parameter defaults
        );

    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

    }

The problem is, if I type /api/TestAPI I successfully see "Hello World", however, /api/TestAPI/7 gives the following exception message: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.

I have 1 result from the database that matches the id "7", which it should be returning. I'm not sure what I'm doing wrong. Anyone can help?

هل كانت مفيدة؟

المحلول

Map to a model. You really should not try to serialize an active EF object. There are many reasons it can fail. As pointed out it could be because it has lazy properties, but you could also have loops in the object. Just map what you need to a model.

public CoursModel Get(int id)
{
    using (SSDEntities Entity = new SSDEntities())
    return Entity.Courses.SingleOrDefault<Cours>(a => a.ID == id)
    .Select(x=> new CoursModel()
         { MAP STUFF HERE });
}

نصائح أخرى

You are returning an object that's controlled by Entity Framework... there's going to be at least two issues here:

  1. The exact error The 'ObjectContent1' type failed to serialize... is caused if the entity class has any IQueryable<T> / IEnumerable<T> / ICollection<T> properties that are lazy-loaded projections from EF. The serializer cannot handle these.
  2. If you get past that, you're also disposing the data context, so if the serializer tries to resolve any other lazy-loaded properties, it will fail.

Before you send an object out the door with WebAPI, you want to strip it down to the barest object with only the properties you know you need. You can either do this with a set of model classes in your web project that map back and forth to your EF classes (see @CrazyDart's answer); or project anonymous objects like so:

return new 
{
    WantedProperty = entity.SomeProperty
};

(Note you'll need to change the WebAPI return type to object for this to work.)

In recent projects I've seen the developers take the approach of returning anonymous objects and for methods that take arguments, using a dynamic argument and handling the JSON decomposition in the controller. For small to medium-ish projects this seems to be very efficient. For more formal / larger projects, a proper framework around it with mapping may make more sense.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top