Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net WebApi OData Actions that return an Queryable

I want to achieve something close to the RateProduct action described in: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-actions

In that tutorial it is defined as:

[HttpPost]
public int RateProduct([FromODataUri] int key, ODataActionParameters parameters) 
{ 
    // ...
}

ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Product>("Products");

// New Code
ActionConfiguration rateProduct = modelBuilder.Entity<Product>().Action("RateProduct");
rateProduct.Parameter<int>("Rating");
rateProduct.Returns<int>();

However, I have the use case of a Location entity that is smart enough to return other Locations within a certain radius around it. It should roughly be like this:

[HttpPost]
public IQueryable<Location> GetLocationsWithinRadius([FromODataUri] int key, ODataActionParameters parameters) 
{ 
    // Get the Location instance intended to be the center of the radius by using the key
    // Do a radius search around it using (int)parameters["radius"] as the radius
    // return the IQueryable<Location> of all location found within that radius
}

ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Location>("Locations");

// New Code
ActionConfiguration getLocations = modelBuilder.Entity<Location>().Action("GetLocationsWithinRadius");
getLocations.Parameter<int>("radius");
getLocations.Returns<IQueryable<Location>>();

I would love to get this to work and currently it doesn't work when the the return type is an IQueryable<Location>. If the return type is a primitive like an int, then it works, otherwise it gives the following error when I create a post in fiddler (the post is something like http://localhost:2663/odata/Locations(2112)/GetLocationsWithinRadius and the Request Body is {radius: 50}):

{
  "odata.error":{
    "code":"","message":{
      "lang":"en-US","value":"An error has occurred."
    },"innererror":{
      "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata=minimalmetadata; streaming=true; charset=utf-8'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
        "message":"The related entity set could not be found from the OData path. The related entity set is required to serialize the payload.","type":"System.Runtime.Serialization.SerializationException","stacktrace":"   at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)\r\n   at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.<>c__DisplayClassa.<WriteToStreamAsync>b__9()\r\n   at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)"
      }
    }
  }
}

Is it possible to do what I am trying to accomplish? And if it is, dare I ask if the returned IQueryable<Location> becomes composable with odata paramaters...(that would be nice)?

Thanks

like image 209
t316 Avatar asked Jun 17 '13 18:06

t316


People also ask

What is the use of $expand in OData?

OData expand functionality can be used to query related data. For example, to get the Course data for each Enrollment entity, include ?$ expand=course at the end of the request path: This tutorial uses Postman to test the web API.

What is $value in OData?

The $value option is used to get individual properties of an Entity. There are two ways to get individual properties from an entity. We can get the response in either OData format or get the raw value of the property. We need to add method to the controller named GetProperty here property is a name of the property.


1 Answers

Looks like your action configuration is incorrect. Try the following and see if it works:

//getLocations.Returns<IQueryable<Location>>();
getLocations.ReturnsCollectionFromEntitySet<Location>("Locations");
like image 190
Kiran Avatar answered Oct 04 '22 06:10

Kiran