WEB API ODATA - GET on properties

Topics: ASP.NET Web API
Mar 1, 2013 at 1:57 PM
Edited Mar 1, 2013 at 2:00 PM
Hi All!

We are having the following problem:
  1. We have an EnrollmentController derived from EntitySetController and if we send GET request for /Enrollments('<guid id>') it works fine.
  2. When we send GET request to /Enrollments('<guid id>')/Status to fetch just a status of the enrollment, we receive the following error:
{
"odata.error":{
"code":"Not implemented.","message":{
  "lang":"en-US","value":"This service doesn't support OData requests in the form '~/entityset/key/property'."
}
}
}
  1. We have tried to tackle this issue the following way
Created method HttpResponseMessage GetStatus(string key) in the EnrollmentController,
registered Status as an EntitySet (only then it started to work!) in the ODataModelBuilder.

It started to return Status in response to /Enrollments('<guid id>')/Status requests, but when i'm sending request to /Enrollments('<guid id>') the response does not contain Status anymore- just a link to it.


Please advise how to tacke this problem.

Thanks,
Aliaksandr.
Coordinator
Mar 1, 2013 at 8:56 PM
Sounds like you are doing all of the right things, but you are hitting some limitations in both the OData protocol spec and the level of protocol support in ASP.NET Web API.

To enable the Status navigation property you need Status to be an EntitySet. There really isn't a first-class way to model containment in OData currently (where one entity is a sub-entity of another), but I believe there is work in progress to address this in a future version.

Once you have your navigation property all setup then the Status will start showing up as a link. Normally you could ask the endpoint to inline the Status using $expand, but this isn't supported yet in ASP.NET Web API OData. We will support $expand in our next release.

Daniel Roth
Mar 4, 2013 at 6:41 AM
Dan,

Thanks for your quick reply.

What we want however is exposing regular properties, not navigation properties.

We are trying to move our code from WCF Data Services Toolkit to WEB API ODATA and are blocked by the fact that partial get for a property is no longer supported.
However everything works fine in WCF Data Services Toolkit.

Could you give us a workaround that does not assume using Navigation properties?
Mar 4, 2013 at 12:05 PM
Sounds like you are looking for the OData $expand query option which is not supported yet.

On Mon, Mar 4, 2013 at 1:41 AM, aliaksandr_pedzko <notifications@codeplex.com> wrote:

From: aliaksandr_pedzko

Dan,

Thanks for your quick reply.

What we want however is exposing regular properties, not navigation properties.

We are trying to move our code from WCF Data Services Toolkit to WEB API ODATA and are blocked by the fact that partial get for a property is no longer supported.
However everything works fine in WCF Data Services Toolkit.

Could you give us a workaround that does not assume using Navigation properties?

Read the full discussion online.

To add a post to this discussion, reply to this email (ASPNETWebStack@discussions.codeplex.com)

To start a new discussion for this project, email ASPNETWebStack@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com




--
----------------------------------------------------------
Brian Noyes
CTO, Solliance: http://solliance.net
Microsoft Regional Director / MVP
Pluralsight Author: http://pluralsight.com
+1 703-447-3712
@briannoyes
----------------------------------------------------------
Mar 4, 2013 at 12:27 PM
Well, as i already wrote, we are considering migration from WCF Data Services Toolkit to WEB API ODATA.
Support for GET requests in the form of Entity(key)/Property is something that blocks us.

We are getting the following error:

This service doesn't support OData requests in the form '~/entityset/key/property'.

We are not talking about the expand option here.
Mar 4, 2013 at 7:22 PM
Web API OData doesn’t make any assumptions about the under lying data provider. We don’t handle the complete OData uri space out-of-the-box. We only handle routing for urls that are commonly used and generated by WCF DS client. The customer though has the choice of supporting OData urls that he wants. We don’t handle structural property access urls in our default routing. We only handle routing for navigation property access.

For this scenario, you have broadly these options with web API,
  1. Implement a routing convention to route ~/entityset/key/property to Get<PropertyName> on the controller and implement Get<properyName> for each and every structural property. This gives the controller the complete flexibility of choosing which properties to support and how to support. But this could be cost prohibitive if your model has too many properties.
  2. Implement a routing convention to route ~/entityset/key/property to GetProperty(TKey key, string propertyName) and then use reflection or whatever is the mechanism for getting data from your provider on your controllers. You could do it once in the base class controller.
  3. Don’t bother implementing a routing convention even. Just implement the GetProperty(TKey key, string propertyName) in HandleUnmappedRequests(). HandleUnmappedRequests as the name suggests is called for all odata requests that are not handled by the default routing conventions that we ship.
I have a sample for the option 3 here. It might be sufficient for your scenario or at the least would steer you in the right direction if you chose to implement 1 or 2. Let me know if you need more help.
Mar 5, 2013 at 10:34 AM
Edited Mar 5, 2013 at 10:34 AM
Hi!

Thanks for the assist.

The issue has been fixed with the code below:

public class EnrollmentsController : EntitySetController<Enrollment, string>
{

// other methods removed for better readability

// POC implementation of partial GET
    // currently works only for Enrollment/Status
    public override HttpResponseMessage HandleUnmappedRequest(ODataPath odataPath)
    {

        if (odataPath.PathTemplate == "~/entityset/key/property" ||odataPath.PathTemplate == "~/entityset/key/cast/property")
        {
            //string propertyName = (odataPath.Segments.Last() as PropertyAccessPathSegment).PropertyName;
            string key = (odataPath.Segments[1] as KeyValuePathSegment).Value;

            var enrollment = _repository.GetOne(NormalizeKey(key));
            return Request.CreateResponse(HttpStatusCode.OK, enrollment.Status);
        }
        return base.HandleUnmappedRequest(odataPath);
    }

    private string NormalizeKey(string key)
    {
        if(key.StartsWith("'"))
        {
            return key.Substring(1, key.Length - 2);
        }

        return key;
    }
}
Apr 19, 2013 at 10:33 PM
Has support for $expand been released yet? I'm using Microsoft.AspNet.WebApi.OData 4.0.1 and Microsoft.Data.OData 5.4.0 and my navigation properties aren't being included in the response.
Coordinator
Apr 19, 2013 at 10:44 PM
Not yet. It actually hasn't even been checked in yet. We are waiting for an updated release of ODataLib to be published first. We expect to have a public preview release you can try out late in June.

Daniel Roth
Apr 25, 2013 at 2:23 AM
June... Hmmm - I was hoping it was this week based on what I saw on StackOverflow as per http://stackoverflow.com/a/15931005/1053381. I myself don't really need $expand in that I don't need to give the client the ability to include extra data, but I would at least like to be able to send back some navigation properties that the server wants to include.

For example, if I select from my Patients controller I'd like to be able to return back some PatientVisit instances - much like Orders and OrderDetails except that whilst I'd rarely want to expose OrderDetails via its own controller I probably would want to have PatientVisits exposed via a separate controller for separate querying & filtering. That StackOverflow post mentioned complexTypes as a way of making this happen. If I do that, can I still expose a complex type via a controller? Is there a way of adjusting the formatters to include non-null navigation properties? I've tried doing this myself and quickly get lost in the source. I think in the past JSON would include them but ATOM wouldn't, although that was in the really old WebAPI OData support which is not like how it's implemented today. I tried adapting Pete Goo's $expand code but after a few hours realised that this year's OData support is too different... (http://blog.petegoo.com/index.php/2012/03/11/supporting-odata-expands-for-ef-includes-in-asp-net-web-api/)

Any pointers? :)
Coordinator
Apr 25, 2013 at 4:47 PM
Well, $expand will show up in our public nightly builds in the next week or two. June is when we will publish an official preview package on nuget.org.

Daniel Roth
Apr 26, 2013 at 2:30 AM
Hi Daniel,

Thanks - I'll keep an eye on the commit history and switch to nightly builds. I tried using nightly builds last week to play with the batch support but ran across issues with ODataLib - probably due to the version you referenced not quite being available. Anyway, no big deal. Thanks for replying!

Cheers,
Ian