Using ODataLib to call a WCF Data Services service operation and JSON
Asked Answered
C

2

0

I have searched far and wide and been completely unable to find any good samples or tutorials of how to call service operations using the ODataLib. I've seen several that tell me how to get entities and entity sets and that's great, but in order to call a service operation.

I'm almost positive that I need to use something other than an ODataEntry, ODataFeed or ODataNavigationLink object. I've opened up the library in JustDecompile and see classes like ODataAction and ODataFunction but can't figure out how to use them.

My needs are pretty simple: I need to call WCF Data Services 5.0 service operations and I need to do it using JSON.

I'm also aware that the upcoming release of the WCF Data Services Client library is going to support JSON but unfortunately I have to code this up like yesterday. Additionally, out of desperation I even tried implementing the RC version (gasp) using Mark Stafford's JSON light sample but didn't really understand how it works.

Any help or direction would be GREATLY appreciated! (Especially if this comes up on your screen, Mark!)

Thanks! J

Colocynth answered 13/7, 2012 at 19:33 Comment(0)
H
2

The choice between ODataLib and WCF Data Services (which depends on ODataLib) as a client often boils down to the need for control. If your use case is straightforward and you need the most common functionality, WCF DS is probably a good fit. If you need advanced functionality or precise control over how a payload is read, ODataLib may be the better match. All that said, Vitek has already covered conceptually how you would read a service operation using ODataLib.

WCF DS will make reading JSON Light much easier in version 5.1. I will blog about this sometime this week, but the sample you referenced is what you'll need to do for this RC. There is only one new call in the sample I put together - the call to context.Format.UseJson(Func<Uri,ModelResolverResult>). Let's talk about why this call is necessary first. OData (at least in the Microsoft world) plays nice with strong typing. $metadata is a good example of OData describing the data model it is working with. With an Atom payload or even a JSON Verbose payload, much of that type information was carried in the payload. With JSON Light the goal was to strip as much of that metadata out of "transport" payloads as possible.

If the metadata isn't available in-band, it must be made available out-of-band. This is the fundamental requirement behind the signature of the call to UseJson. In essence, whenever WCF DS needs metadata it will go look up the model for a given URI. If it can't find that model it will eventually dial up the metadata to full. We want to preempt that as it will bloat the payload. We can preempt it by telling WCF DS how to resolve the model ahead of time. This is what the majority of the sample is doing.

Walking through the sample logically (yes, I know there's a number of other optimizations that could have been made - the sample was mostly optimized for readability):

  • If the model hasn't been resolved in the past
    • Construct a new XmlReader for the call to EdmxReader.TryParse
    • Name some values for the out params in EdmxReader.TryParse
    • Invoke EdmxReader.TryParse
      • If the call succeeded, cache the parsed model in a local dictionary (parsing is an expensive operation right now)
      • If the call failed, put together the errors and throw
  • Grab the correct model from the cached models and return it in a ModelResolverResult wrapper

Hopefully that makes sense. If it doesn't, I'd love to hear why so that I can make the blog post clearer. And remember, this will get much simpler by the time we release these bits to production.

Haematoid answered 16/7, 2012 at 15:22 Comment(1)
What you've said makes perfect sense and actually completely clears up the meaning of the sample. As per usual you've managed to bring it down to my level and I thank you very much for that!Colocynth
C
2

ODataLib doesn't know (and is not supposed to know) that it's reading a response of a service operation. The only thing which matters if what payload kind you want to read.

It depends on what the service operation returns. If it returns a single entry then use ODataLib just like reading a single entry payloads (for example ~/Products(0)) since the wire format will be the same. If the service operation returns a collection of entities, then read it like a feed.

If the service operation returns a single primitive or complex value, you can use ODataMessageReader.ReadProperty. I know the name of the method is a bit misleading but that's again because a property payload (like ~/Products(0)/Name) and a service operation returning a primitive or complex type use the exact same payload format. In this case you should ignore the name of the property returned (it will likely be the name of the service operation).

If the service operation returns a collection of primitive or complex values, you can use the ODataMessageReader.CreateODataCollectionReader. That will return ODataCollectionReader reader which you use in a very similar way of ODataReader. The interesting things it reports are items of the collection in question (the API in this case is pretty easy to understand).

It should not matter whether you need to read ATOM or JSON, that's up to you, the API is the same.

Crowson answered 15/7, 2012 at 17:59 Comment(0)
H
2

The choice between ODataLib and WCF Data Services (which depends on ODataLib) as a client often boils down to the need for control. If your use case is straightforward and you need the most common functionality, WCF DS is probably a good fit. If you need advanced functionality or precise control over how a payload is read, ODataLib may be the better match. All that said, Vitek has already covered conceptually how you would read a service operation using ODataLib.

WCF DS will make reading JSON Light much easier in version 5.1. I will blog about this sometime this week, but the sample you referenced is what you'll need to do for this RC. There is only one new call in the sample I put together - the call to context.Format.UseJson(Func<Uri,ModelResolverResult>). Let's talk about why this call is necessary first. OData (at least in the Microsoft world) plays nice with strong typing. $metadata is a good example of OData describing the data model it is working with. With an Atom payload or even a JSON Verbose payload, much of that type information was carried in the payload. With JSON Light the goal was to strip as much of that metadata out of "transport" payloads as possible.

If the metadata isn't available in-band, it must be made available out-of-band. This is the fundamental requirement behind the signature of the call to UseJson. In essence, whenever WCF DS needs metadata it will go look up the model for a given URI. If it can't find that model it will eventually dial up the metadata to full. We want to preempt that as it will bloat the payload. We can preempt it by telling WCF DS how to resolve the model ahead of time. This is what the majority of the sample is doing.

Walking through the sample logically (yes, I know there's a number of other optimizations that could have been made - the sample was mostly optimized for readability):

  • If the model hasn't been resolved in the past
    • Construct a new XmlReader for the call to EdmxReader.TryParse
    • Name some values for the out params in EdmxReader.TryParse
    • Invoke EdmxReader.TryParse
      • If the call succeeded, cache the parsed model in a local dictionary (parsing is an expensive operation right now)
      • If the call failed, put together the errors and throw
  • Grab the correct model from the cached models and return it in a ModelResolverResult wrapper

Hopefully that makes sense. If it doesn't, I'd love to hear why so that I can make the blog post clearer. And remember, this will get much simpler by the time we release these bits to production.

Haematoid answered 16/7, 2012 at 15:22 Comment(1)
What you've said makes perfect sense and actually completely clears up the meaning of the sample. As per usual you've managed to bring it down to my level and I thank you very much for that!Colocynth

© 2022 - 2024 — McMap. All rights reserved.